wm_adsp.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  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. #include <linux/module.h>
  13. #include <linux/moduleparam.h>
  14. #include <linux/init.h>
  15. #include <linux/delay.h>
  16. #include <linux/firmware.h>
  17. #include <linux/pm.h>
  18. #include <linux/pm_runtime.h>
  19. #include <linux/regmap.h>
  20. #include <linux/regulator/consumer.h>
  21. #include <linux/slab.h>
  22. #include <sound/core.h>
  23. #include <sound/pcm.h>
  24. #include <sound/pcm_params.h>
  25. #include <sound/soc.h>
  26. #include <sound/jack.h>
  27. #include <sound/initval.h>
  28. #include <sound/tlv.h>
  29. #include <linux/mfd/arizona/registers.h>
  30. #include "wm_adsp.h"
  31. #define adsp_crit(_dsp, fmt, ...) \
  32. dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
  33. #define adsp_err(_dsp, fmt, ...) \
  34. dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
  35. #define adsp_warn(_dsp, fmt, ...) \
  36. dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
  37. #define adsp_info(_dsp, fmt, ...) \
  38. dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
  39. #define adsp_dbg(_dsp, fmt, ...) \
  40. dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
  41. #define ADSP1_CONTROL_1 0x00
  42. #define ADSP1_CONTROL_2 0x02
  43. #define ADSP1_CONTROL_3 0x03
  44. #define ADSP1_CONTROL_4 0x04
  45. #define ADSP1_CONTROL_5 0x06
  46. #define ADSP1_CONTROL_6 0x07
  47. #define ADSP1_CONTROL_7 0x08
  48. #define ADSP1_CONTROL_8 0x09
  49. #define ADSP1_CONTROL_9 0x0A
  50. #define ADSP1_CONTROL_10 0x0B
  51. #define ADSP1_CONTROL_11 0x0C
  52. #define ADSP1_CONTROL_12 0x0D
  53. #define ADSP1_CONTROL_13 0x0F
  54. #define ADSP1_CONTROL_14 0x10
  55. #define ADSP1_CONTROL_15 0x11
  56. #define ADSP1_CONTROL_16 0x12
  57. #define ADSP1_CONTROL_17 0x13
  58. #define ADSP1_CONTROL_18 0x14
  59. #define ADSP1_CONTROL_19 0x16
  60. #define ADSP1_CONTROL_20 0x17
  61. #define ADSP1_CONTROL_21 0x18
  62. #define ADSP1_CONTROL_22 0x1A
  63. #define ADSP1_CONTROL_23 0x1B
  64. #define ADSP1_CONTROL_24 0x1C
  65. #define ADSP1_CONTROL_25 0x1E
  66. #define ADSP1_CONTROL_26 0x20
  67. #define ADSP1_CONTROL_27 0x21
  68. #define ADSP1_CONTROL_28 0x22
  69. #define ADSP1_CONTROL_29 0x23
  70. #define ADSP1_CONTROL_30 0x24
  71. #define ADSP1_CONTROL_31 0x26
  72. /*
  73. * ADSP1 Control 19
  74. */
  75. #define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  76. #define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  77. #define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */
  78. /*
  79. * ADSP1 Control 30
  80. */
  81. #define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */
  82. #define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */
  83. #define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */
  84. #define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */
  85. #define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
  86. #define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
  87. #define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
  88. #define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
  89. #define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
  90. #define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
  91. #define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
  92. #define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
  93. #define ADSP1_START 0x0001 /* DSP1_START */
  94. #define ADSP1_START_MASK 0x0001 /* DSP1_START */
  95. #define ADSP1_START_SHIFT 0 /* DSP1_START */
  96. #define ADSP1_START_WIDTH 1 /* DSP1_START */
  97. #define ADSP2_CONTROL 0
  98. #define ADSP2_CLOCKING 1
  99. #define ADSP2_STATUS1 4
  100. /*
  101. * ADSP2 Control
  102. */
  103. #define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */
  104. #define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */
  105. #define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */
  106. #define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */
  107. #define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
  108. #define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
  109. #define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
  110. #define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
  111. #define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
  112. #define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
  113. #define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
  114. #define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
  115. #define ADSP2_START 0x0001 /* DSP1_START */
  116. #define ADSP2_START_MASK 0x0001 /* DSP1_START */
  117. #define ADSP2_START_SHIFT 0 /* DSP1_START */
  118. #define ADSP2_START_WIDTH 1 /* DSP1_START */
  119. /*
  120. * ADSP2 clocking
  121. */
  122. #define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */
  123. #define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */
  124. #define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */
  125. /*
  126. * ADSP2 Status 1
  127. */
  128. #define ADSP2_RAM_RDY 0x0001
  129. #define ADSP2_RAM_RDY_MASK 0x0001
  130. #define ADSP2_RAM_RDY_SHIFT 0
  131. #define ADSP2_RAM_RDY_WIDTH 1
  132. #define WM_ADSP_NUM_FW 3
  133. static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
  134. "MBC/VSS", "Tx", "Rx ANC"
  135. };
  136. static struct {
  137. const char *file;
  138. } wm_adsp_fw[WM_ADSP_NUM_FW] = {
  139. { .file = "mbc-vss" },
  140. { .file = "tx" },
  141. { .file = "rx-anc" },
  142. };
  143. static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
  144. struct snd_ctl_elem_value *ucontrol)
  145. {
  146. struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  147. struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  148. struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
  149. ucontrol->value.integer.value[0] = adsp[e->shift_l].fw;
  150. return 0;
  151. }
  152. static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
  153. struct snd_ctl_elem_value *ucontrol)
  154. {
  155. struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
  156. struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  157. struct wm_adsp *adsp = snd_soc_codec_get_drvdata(codec);
  158. if (ucontrol->value.integer.value[0] == adsp[e->shift_l].fw)
  159. return 0;
  160. if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW)
  161. return -EINVAL;
  162. if (adsp[e->shift_l].running)
  163. return -EBUSY;
  164. adsp->fw = ucontrol->value.integer.value[0];
  165. return 0;
  166. }
  167. static const struct soc_enum wm_adsp_fw_enum[] = {
  168. SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
  169. SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
  170. SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
  171. SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
  172. };
  173. const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
  174. SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
  175. wm_adsp_fw_get, wm_adsp_fw_put),
  176. SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
  177. wm_adsp_fw_get, wm_adsp_fw_put),
  178. SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
  179. wm_adsp_fw_get, wm_adsp_fw_put),
  180. SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
  181. wm_adsp_fw_get, wm_adsp_fw_put),
  182. };
  183. EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
  184. static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
  185. int type)
  186. {
  187. int i;
  188. for (i = 0; i < dsp->num_mems; i++)
  189. if (dsp->mem[i].type == type)
  190. return &dsp->mem[i];
  191. return NULL;
  192. }
  193. static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
  194. unsigned int offset)
  195. {
  196. switch (region->type) {
  197. case WMFW_ADSP1_PM:
  198. return region->base + (offset * 3);
  199. case WMFW_ADSP1_DM:
  200. return region->base + (offset * 2);
  201. case WMFW_ADSP2_XM:
  202. return region->base + (offset * 2);
  203. case WMFW_ADSP2_YM:
  204. return region->base + (offset * 2);
  205. case WMFW_ADSP1_ZM:
  206. return region->base + (offset * 2);
  207. default:
  208. WARN_ON(NULL != "Unknown memory region type");
  209. return offset;
  210. }
  211. }
  212. static int wm_adsp_load(struct wm_adsp *dsp)
  213. {
  214. const struct firmware *firmware;
  215. struct regmap *regmap = dsp->regmap;
  216. unsigned int pos = 0;
  217. const struct wmfw_header *header;
  218. const struct wmfw_adsp1_sizes *adsp1_sizes;
  219. const struct wmfw_adsp2_sizes *adsp2_sizes;
  220. const struct wmfw_footer *footer;
  221. const struct wmfw_region *region;
  222. const struct wm_adsp_region *mem;
  223. const char *region_name;
  224. char *file, *text;
  225. unsigned int reg;
  226. int regions = 0;
  227. int ret, offset, type, sizes;
  228. file = kzalloc(PAGE_SIZE, GFP_KERNEL);
  229. if (file == NULL)
  230. return -ENOMEM;
  231. snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
  232. wm_adsp_fw[dsp->fw].file);
  233. file[PAGE_SIZE - 1] = '\0';
  234. ret = request_firmware(&firmware, file, dsp->dev);
  235. if (ret != 0) {
  236. adsp_err(dsp, "Failed to request '%s'\n", file);
  237. goto out;
  238. }
  239. ret = -EINVAL;
  240. pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
  241. if (pos >= firmware->size) {
  242. adsp_err(dsp, "%s: file too short, %zu bytes\n",
  243. file, firmware->size);
  244. goto out_fw;
  245. }
  246. header = (void*)&firmware->data[0];
  247. if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
  248. adsp_err(dsp, "%s: invalid magic\n", file);
  249. goto out_fw;
  250. }
  251. if (header->ver != 0) {
  252. adsp_err(dsp, "%s: unknown file format %d\n",
  253. file, header->ver);
  254. goto out_fw;
  255. }
  256. if (header->core != dsp->type) {
  257. adsp_err(dsp, "%s: invalid core %d != %d\n",
  258. file, header->core, dsp->type);
  259. goto out_fw;
  260. }
  261. switch (dsp->type) {
  262. case WMFW_ADSP1:
  263. pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
  264. adsp1_sizes = (void *)&(header[1]);
  265. footer = (void *)&(adsp1_sizes[1]);
  266. sizes = sizeof(*adsp1_sizes);
  267. adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
  268. file, le32_to_cpu(adsp1_sizes->dm),
  269. le32_to_cpu(adsp1_sizes->pm),
  270. le32_to_cpu(adsp1_sizes->zm));
  271. break;
  272. case WMFW_ADSP2:
  273. pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
  274. adsp2_sizes = (void *)&(header[1]);
  275. footer = (void *)&(adsp2_sizes[1]);
  276. sizes = sizeof(*adsp2_sizes);
  277. adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
  278. file, le32_to_cpu(adsp2_sizes->xm),
  279. le32_to_cpu(adsp2_sizes->ym),
  280. le32_to_cpu(adsp2_sizes->pm),
  281. le32_to_cpu(adsp2_sizes->zm));
  282. break;
  283. default:
  284. BUG_ON(NULL == "Unknown DSP type");
  285. goto out_fw;
  286. }
  287. if (le32_to_cpu(header->len) != sizeof(*header) +
  288. sizes + sizeof(*footer)) {
  289. adsp_err(dsp, "%s: unexpected header length %d\n",
  290. file, le32_to_cpu(header->len));
  291. goto out_fw;
  292. }
  293. adsp_dbg(dsp, "%s: timestamp %llu\n", file,
  294. le64_to_cpu(footer->timestamp));
  295. while (pos < firmware->size &&
  296. pos - firmware->size > sizeof(*region)) {
  297. region = (void *)&(firmware->data[pos]);
  298. region_name = "Unknown";
  299. reg = 0;
  300. text = NULL;
  301. offset = le32_to_cpu(region->offset) & 0xffffff;
  302. type = be32_to_cpu(region->type) & 0xff;
  303. mem = wm_adsp_find_region(dsp, type);
  304. switch (type) {
  305. case WMFW_NAME_TEXT:
  306. region_name = "Firmware name";
  307. text = kzalloc(le32_to_cpu(region->len) + 1,
  308. GFP_KERNEL);
  309. break;
  310. case WMFW_INFO_TEXT:
  311. region_name = "Information";
  312. text = kzalloc(le32_to_cpu(region->len) + 1,
  313. GFP_KERNEL);
  314. break;
  315. case WMFW_ABSOLUTE:
  316. region_name = "Absolute";
  317. reg = offset;
  318. break;
  319. case WMFW_ADSP1_PM:
  320. BUG_ON(!mem);
  321. region_name = "PM";
  322. reg = wm_adsp_region_to_reg(mem, offset);
  323. break;
  324. case WMFW_ADSP1_DM:
  325. BUG_ON(!mem);
  326. region_name = "DM";
  327. reg = wm_adsp_region_to_reg(mem, offset);
  328. break;
  329. case WMFW_ADSP2_XM:
  330. BUG_ON(!mem);
  331. region_name = "XM";
  332. reg = wm_adsp_region_to_reg(mem, offset);
  333. break;
  334. case WMFW_ADSP2_YM:
  335. BUG_ON(!mem);
  336. region_name = "YM";
  337. reg = wm_adsp_region_to_reg(mem, offset);
  338. break;
  339. case WMFW_ADSP1_ZM:
  340. BUG_ON(!mem);
  341. region_name = "ZM";
  342. reg = wm_adsp_region_to_reg(mem, offset);
  343. break;
  344. default:
  345. adsp_warn(dsp,
  346. "%s.%d: Unknown region type %x at %d(%x)\n",
  347. file, regions, type, pos, pos);
  348. break;
  349. }
  350. adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file,
  351. regions, le32_to_cpu(region->len), offset,
  352. region_name);
  353. if (text) {
  354. memcpy(text, region->data, le32_to_cpu(region->len));
  355. adsp_info(dsp, "%s: %s\n", file, text);
  356. kfree(text);
  357. }
  358. if (reg) {
  359. ret = regmap_raw_write(regmap, reg, region->data,
  360. le32_to_cpu(region->len));
  361. if (ret != 0) {
  362. adsp_err(dsp,
  363. "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
  364. file, regions,
  365. le32_to_cpu(region->len), offset,
  366. region_name, ret);
  367. goto out_fw;
  368. }
  369. }
  370. pos += le32_to_cpu(region->len) + sizeof(*region);
  371. regions++;
  372. }
  373. if (pos > firmware->size)
  374. adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
  375. file, regions, pos - firmware->size);
  376. out_fw:
  377. release_firmware(firmware);
  378. out:
  379. kfree(file);
  380. return ret;
  381. }
  382. static int wm_adsp_setup_algs(struct wm_adsp *dsp)
  383. {
  384. struct regmap *regmap = dsp->regmap;
  385. struct wmfw_adsp1_id_hdr adsp1_id;
  386. struct wmfw_adsp2_id_hdr adsp2_id;
  387. struct wmfw_adsp1_alg_hdr *adsp1_alg;
  388. struct wmfw_adsp2_alg_hdr *adsp2_alg;
  389. void *alg, *buf;
  390. struct wm_adsp_alg_region *region;
  391. const struct wm_adsp_region *mem;
  392. unsigned int pos, term;
  393. size_t algs, buf_size;
  394. __be32 val;
  395. int i, ret;
  396. switch (dsp->type) {
  397. case WMFW_ADSP1:
  398. mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
  399. break;
  400. case WMFW_ADSP2:
  401. mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
  402. break;
  403. default:
  404. mem = NULL;
  405. break;
  406. }
  407. if (mem == NULL) {
  408. BUG_ON(mem != NULL);
  409. return -EINVAL;
  410. }
  411. switch (dsp->type) {
  412. case WMFW_ADSP1:
  413. ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
  414. sizeof(adsp1_id));
  415. if (ret != 0) {
  416. adsp_err(dsp, "Failed to read algorithm info: %d\n",
  417. ret);
  418. return ret;
  419. }
  420. buf = &adsp1_id;
  421. buf_size = sizeof(adsp1_id);
  422. algs = be32_to_cpu(adsp1_id.algs);
  423. adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
  424. be32_to_cpu(adsp1_id.fw.id),
  425. (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
  426. (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
  427. be32_to_cpu(adsp1_id.fw.ver) & 0xff,
  428. algs);
  429. pos = sizeof(adsp1_id) / 2;
  430. term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
  431. break;
  432. case WMFW_ADSP2:
  433. ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
  434. sizeof(adsp2_id));
  435. if (ret != 0) {
  436. adsp_err(dsp, "Failed to read algorithm info: %d\n",
  437. ret);
  438. return ret;
  439. }
  440. buf = &adsp2_id;
  441. buf_size = sizeof(adsp2_id);
  442. algs = be32_to_cpu(adsp2_id.algs);
  443. adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
  444. be32_to_cpu(adsp2_id.fw.id),
  445. (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
  446. (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
  447. be32_to_cpu(adsp2_id.fw.ver) & 0xff,
  448. algs);
  449. pos = sizeof(adsp2_id) / 2;
  450. term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
  451. break;
  452. default:
  453. BUG_ON(NULL == "Unknown DSP type");
  454. return -EINVAL;
  455. }
  456. if (algs == 0) {
  457. adsp_err(dsp, "No algorithms\n");
  458. return -EINVAL;
  459. }
  460. if (algs > 1024) {
  461. adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
  462. print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
  463. buf, buf_size);
  464. return -EINVAL;
  465. }
  466. /* Read the terminator first to validate the length */
  467. ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
  468. if (ret != 0) {
  469. adsp_err(dsp, "Failed to read algorithm list end: %d\n",
  470. ret);
  471. return ret;
  472. }
  473. if (be32_to_cpu(val) != 0xbedead)
  474. adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
  475. term, be32_to_cpu(val));
  476. alg = kzalloc((term - pos) * 2, GFP_KERNEL);
  477. if (!alg)
  478. return -ENOMEM;
  479. ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
  480. if (ret != 0) {
  481. adsp_err(dsp, "Failed to read algorithm list: %d\n",
  482. ret);
  483. goto out;
  484. }
  485. adsp1_alg = alg;
  486. adsp2_alg = alg;
  487. for (i = 0; i < algs; i++) {
  488. switch (dsp->type) {
  489. case WMFW_ADSP1:
  490. adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
  491. i, be32_to_cpu(adsp1_alg[i].alg.id),
  492. (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
  493. (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
  494. be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
  495. be32_to_cpu(adsp1_alg[i].dm),
  496. be32_to_cpu(adsp1_alg[i].zm));
  497. if (adsp1_alg[i].dm) {
  498. region = kzalloc(sizeof(*region), GFP_KERNEL);
  499. if (!region)
  500. return -ENOMEM;
  501. region->type = WMFW_ADSP1_DM;
  502. region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
  503. region->base = be32_to_cpu(adsp1_alg[i].dm);
  504. list_add_tail(&region->list,
  505. &dsp->alg_regions);
  506. }
  507. if (adsp1_alg[i].zm) {
  508. region = kzalloc(sizeof(*region), GFP_KERNEL);
  509. if (!region)
  510. return -ENOMEM;
  511. region->type = WMFW_ADSP1_ZM;
  512. region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
  513. region->base = be32_to_cpu(adsp1_alg[i].zm);
  514. list_add_tail(&region->list,
  515. &dsp->alg_regions);
  516. }
  517. break;
  518. case WMFW_ADSP2:
  519. adsp_info(dsp,
  520. "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
  521. i, be32_to_cpu(adsp2_alg[i].alg.id),
  522. (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
  523. (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
  524. be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
  525. be32_to_cpu(adsp2_alg[i].xm),
  526. be32_to_cpu(adsp2_alg[i].ym),
  527. be32_to_cpu(adsp2_alg[i].zm));
  528. if (adsp2_alg[i].xm) {
  529. region = kzalloc(sizeof(*region), GFP_KERNEL);
  530. if (!region)
  531. return -ENOMEM;
  532. region->type = WMFW_ADSP2_XM;
  533. region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
  534. region->base = be32_to_cpu(adsp2_alg[i].xm);
  535. list_add_tail(&region->list,
  536. &dsp->alg_regions);
  537. }
  538. if (adsp2_alg[i].ym) {
  539. region = kzalloc(sizeof(*region), GFP_KERNEL);
  540. if (!region)
  541. return -ENOMEM;
  542. region->type = WMFW_ADSP2_YM;
  543. region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
  544. region->base = be32_to_cpu(adsp2_alg[i].ym);
  545. list_add_tail(&region->list,
  546. &dsp->alg_regions);
  547. }
  548. if (adsp2_alg[i].zm) {
  549. region = kzalloc(sizeof(*region), GFP_KERNEL);
  550. if (!region)
  551. return -ENOMEM;
  552. region->type = WMFW_ADSP2_ZM;
  553. region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
  554. region->base = be32_to_cpu(adsp2_alg[i].zm);
  555. list_add_tail(&region->list,
  556. &dsp->alg_regions);
  557. }
  558. break;
  559. }
  560. }
  561. out:
  562. kfree(alg);
  563. return ret;
  564. }
  565. static int wm_adsp_load_coeff(struct wm_adsp *dsp)
  566. {
  567. struct regmap *regmap = dsp->regmap;
  568. struct wmfw_coeff_hdr *hdr;
  569. struct wmfw_coeff_item *blk;
  570. const struct firmware *firmware;
  571. const struct wm_adsp_region *mem;
  572. struct wm_adsp_alg_region *alg_region;
  573. const char *region_name;
  574. int ret, pos, blocks, type, offset, reg;
  575. char *file;
  576. file = kzalloc(PAGE_SIZE, GFP_KERNEL);
  577. if (file == NULL)
  578. return -ENOMEM;
  579. snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
  580. wm_adsp_fw[dsp->fw].file);
  581. file[PAGE_SIZE - 1] = '\0';
  582. ret = request_firmware(&firmware, file, dsp->dev);
  583. if (ret != 0) {
  584. adsp_warn(dsp, "Failed to request '%s'\n", file);
  585. ret = 0;
  586. goto out;
  587. }
  588. ret = -EINVAL;
  589. if (sizeof(*hdr) >= firmware->size) {
  590. adsp_err(dsp, "%s: file too short, %zu bytes\n",
  591. file, firmware->size);
  592. goto out_fw;
  593. }
  594. hdr = (void*)&firmware->data[0];
  595. if (memcmp(hdr->magic, "WMDR", 4) != 0) {
  596. adsp_err(dsp, "%s: invalid magic\n", file);
  597. return -EINVAL;
  598. }
  599. adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
  600. (le32_to_cpu(hdr->ver) >> 16) & 0xff,
  601. (le32_to_cpu(hdr->ver) >> 8) & 0xff,
  602. le32_to_cpu(hdr->ver) & 0xff);
  603. pos = le32_to_cpu(hdr->len);
  604. blocks = 0;
  605. while (pos < firmware->size &&
  606. pos - firmware->size > sizeof(*blk)) {
  607. blk = (void*)(&firmware->data[pos]);
  608. type = be32_to_cpu(blk->type) & 0xff;
  609. offset = le32_to_cpu(blk->offset) & 0xffffff;
  610. adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n",
  611. file, blocks, le32_to_cpu(blk->id),
  612. (le32_to_cpu(blk->ver) >> 16) & 0xff,
  613. (le32_to_cpu(blk->ver) >> 8) & 0xff,
  614. le32_to_cpu(blk->ver) & 0xff);
  615. adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n",
  616. file, blocks, le32_to_cpu(blk->len), offset, type);
  617. reg = 0;
  618. region_name = "Unknown";
  619. switch (type) {
  620. case WMFW_NAME_TEXT:
  621. case WMFW_INFO_TEXT:
  622. break;
  623. case WMFW_ABSOLUTE:
  624. region_name = "register";
  625. reg = offset;
  626. break;
  627. case WMFW_ADSP1_DM:
  628. case WMFW_ADSP1_ZM:
  629. case WMFW_ADSP2_XM:
  630. case WMFW_ADSP2_YM:
  631. adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
  632. file, blocks, le32_to_cpu(blk->len),
  633. type, le32_to_cpu(blk->id));
  634. mem = wm_adsp_find_region(dsp, type);
  635. if (!mem) {
  636. adsp_err(dsp, "No base for region %x\n", type);
  637. break;
  638. }
  639. reg = 0;
  640. list_for_each_entry(alg_region,
  641. &dsp->alg_regions, list) {
  642. if (le32_to_cpu(blk->id) == alg_region->alg &&
  643. type == alg_region->type) {
  644. reg = alg_region->base + offset;
  645. reg = wm_adsp_region_to_reg(mem,
  646. reg);
  647. }
  648. }
  649. if (reg == 0)
  650. adsp_err(dsp, "No %x for algorithm %x\n",
  651. type, le32_to_cpu(blk->id));
  652. break;
  653. default:
  654. adsp_err(dsp, "Unknown region type %x\n", type);
  655. break;
  656. }
  657. if (reg) {
  658. ret = regmap_raw_write(regmap, reg, blk->data,
  659. le32_to_cpu(blk->len));
  660. if (ret != 0) {
  661. adsp_err(dsp,
  662. "%s.%d: Failed to write to %x in %s\n",
  663. file, blocks, reg, region_name);
  664. }
  665. }
  666. pos += le32_to_cpu(blk->len) + sizeof(*blk);
  667. blocks++;
  668. }
  669. if (pos > firmware->size)
  670. adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n",
  671. file, blocks, pos - firmware->size);
  672. out_fw:
  673. release_firmware(firmware);
  674. out:
  675. kfree(file);
  676. return 0;
  677. }
  678. int wm_adsp1_init(struct wm_adsp *adsp)
  679. {
  680. INIT_LIST_HEAD(&adsp->alg_regions);
  681. return 0;
  682. }
  683. EXPORT_SYMBOL_GPL(wm_adsp1_init);
  684. int wm_adsp1_event(struct snd_soc_dapm_widget *w,
  685. struct snd_kcontrol *kcontrol,
  686. int event)
  687. {
  688. struct snd_soc_codec *codec = w->codec;
  689. struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
  690. struct wm_adsp *dsp = &dsps[w->shift];
  691. int ret;
  692. switch (event) {
  693. case SND_SOC_DAPM_POST_PMU:
  694. regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
  695. ADSP1_SYS_ENA, ADSP1_SYS_ENA);
  696. ret = wm_adsp_load(dsp);
  697. if (ret != 0)
  698. goto err;
  699. ret = wm_adsp_setup_algs(dsp);
  700. if (ret != 0)
  701. goto err;
  702. ret = wm_adsp_load_coeff(dsp);
  703. if (ret != 0)
  704. goto err;
  705. /* Start the core running */
  706. regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
  707. ADSP1_CORE_ENA | ADSP1_START,
  708. ADSP1_CORE_ENA | ADSP1_START);
  709. break;
  710. case SND_SOC_DAPM_PRE_PMD:
  711. /* Halt the core */
  712. regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
  713. ADSP1_CORE_ENA | ADSP1_START, 0);
  714. regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19,
  715. ADSP1_WDMA_BUFFER_LENGTH_MASK, 0);
  716. regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
  717. ADSP1_SYS_ENA, 0);
  718. break;
  719. default:
  720. break;
  721. }
  722. return 0;
  723. err:
  724. regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
  725. ADSP1_SYS_ENA, 0);
  726. return ret;
  727. }
  728. EXPORT_SYMBOL_GPL(wm_adsp1_event);
  729. static int wm_adsp2_ena(struct wm_adsp *dsp)
  730. {
  731. unsigned int val;
  732. int ret, count;
  733. ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
  734. ADSP2_SYS_ENA, ADSP2_SYS_ENA);
  735. if (ret != 0)
  736. return ret;
  737. /* Wait for the RAM to start, should be near instantaneous */
  738. count = 0;
  739. do {
  740. ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
  741. &val);
  742. if (ret != 0)
  743. return ret;
  744. } while (!(val & ADSP2_RAM_RDY) && ++count < 10);
  745. if (!(val & ADSP2_RAM_RDY)) {
  746. adsp_err(dsp, "Failed to start DSP RAM\n");
  747. return -EBUSY;
  748. }
  749. adsp_dbg(dsp, "RAM ready after %d polls\n", count);
  750. adsp_info(dsp, "RAM ready after %d polls\n", count);
  751. return 0;
  752. }
  753. int wm_adsp2_event(struct snd_soc_dapm_widget *w,
  754. struct snd_kcontrol *kcontrol, int event)
  755. {
  756. struct snd_soc_codec *codec = w->codec;
  757. struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
  758. struct wm_adsp *dsp = &dsps[w->shift];
  759. struct wm_adsp_alg_region *alg_region;
  760. unsigned int val;
  761. int ret;
  762. switch (event) {
  763. case SND_SOC_DAPM_POST_PMU:
  764. /*
  765. * For simplicity set the DSP clock rate to be the
  766. * SYSCLK rate rather than making it configurable.
  767. */
  768. ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
  769. if (ret != 0) {
  770. adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
  771. ret);
  772. return ret;
  773. }
  774. val = (val & ARIZONA_SYSCLK_FREQ_MASK)
  775. >> ARIZONA_SYSCLK_FREQ_SHIFT;
  776. ret = regmap_update_bits(dsp->regmap,
  777. dsp->base + ADSP2_CLOCKING,
  778. ADSP2_CLK_SEL_MASK, val);
  779. if (ret != 0) {
  780. adsp_err(dsp, "Failed to set clock rate: %d\n",
  781. ret);
  782. return ret;
  783. }
  784. if (dsp->dvfs) {
  785. ret = regmap_read(dsp->regmap,
  786. dsp->base + ADSP2_CLOCKING, &val);
  787. if (ret != 0) {
  788. dev_err(dsp->dev,
  789. "Failed to read clocking: %d\n", ret);
  790. return ret;
  791. }
  792. if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
  793. ret = regulator_enable(dsp->dvfs);
  794. if (ret != 0) {
  795. dev_err(dsp->dev,
  796. "Failed to enable supply: %d\n",
  797. ret);
  798. return ret;
  799. }
  800. ret = regulator_set_voltage(dsp->dvfs,
  801. 1800000,
  802. 1800000);
  803. if (ret != 0) {
  804. dev_err(dsp->dev,
  805. "Failed to raise supply: %d\n",
  806. ret);
  807. return ret;
  808. }
  809. }
  810. }
  811. ret = wm_adsp2_ena(dsp);
  812. if (ret != 0)
  813. return ret;
  814. ret = wm_adsp_load(dsp);
  815. if (ret != 0)
  816. goto err;
  817. ret = wm_adsp_setup_algs(dsp);
  818. if (ret != 0)
  819. goto err;
  820. ret = wm_adsp_load_coeff(dsp);
  821. if (ret != 0)
  822. goto err;
  823. ret = regmap_update_bits(dsp->regmap,
  824. dsp->base + ADSP2_CONTROL,
  825. ADSP2_CORE_ENA | ADSP2_START,
  826. ADSP2_CORE_ENA | ADSP2_START);
  827. if (ret != 0)
  828. goto err;
  829. dsp->running = true;
  830. break;
  831. case SND_SOC_DAPM_PRE_PMD:
  832. dsp->running = false;
  833. regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
  834. ADSP2_SYS_ENA | ADSP2_CORE_ENA |
  835. ADSP2_START, 0);
  836. if (dsp->dvfs) {
  837. ret = regulator_set_voltage(dsp->dvfs, 1200000,
  838. 1800000);
  839. if (ret != 0)
  840. dev_warn(dsp->dev,
  841. "Failed to lower supply: %d\n",
  842. ret);
  843. ret = regulator_disable(dsp->dvfs);
  844. if (ret != 0)
  845. dev_err(dsp->dev,
  846. "Failed to enable supply: %d\n",
  847. ret);
  848. }
  849. while (!list_empty(&dsp->alg_regions)) {
  850. alg_region = list_first_entry(&dsp->alg_regions,
  851. struct wm_adsp_alg_region,
  852. list);
  853. list_del(&alg_region->list);
  854. kfree(alg_region);
  855. }
  856. break;
  857. default:
  858. break;
  859. }
  860. return 0;
  861. err:
  862. regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
  863. ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
  864. return ret;
  865. }
  866. EXPORT_SYMBOL_GPL(wm_adsp2_event);
  867. int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
  868. {
  869. int ret;
  870. /*
  871. * Disable the DSP memory by default when in reset for a small
  872. * power saving.
  873. */
  874. ret = regmap_update_bits(adsp->regmap, adsp->base + ADSP2_CONTROL,
  875. ADSP2_MEM_ENA, 0);
  876. if (ret != 0) {
  877. adsp_err(adsp, "Failed to clear memory retention: %d\n", ret);
  878. return ret;
  879. }
  880. INIT_LIST_HEAD(&adsp->alg_regions);
  881. if (dvfs) {
  882. adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
  883. if (IS_ERR(adsp->dvfs)) {
  884. ret = PTR_ERR(adsp->dvfs);
  885. dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
  886. return ret;
  887. }
  888. ret = regulator_enable(adsp->dvfs);
  889. if (ret != 0) {
  890. dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
  891. ret);
  892. return ret;
  893. }
  894. ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
  895. if (ret != 0) {
  896. dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
  897. ret);
  898. return ret;
  899. }
  900. ret = regulator_disable(adsp->dvfs);
  901. if (ret != 0) {
  902. dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
  903. ret);
  904. return ret;
  905. }
  906. }
  907. return 0;
  908. }
  909. EXPORT_SYMBOL_GPL(wm_adsp2_init);