summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm_adsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
-rw-r--r--sound/soc/codecs/wm_adsp.c129
1 files changed, 116 insertions, 13 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index f3f7e75f8628..3470b649c0b2 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -31,6 +31,7 @@
#include <linux/mfd/arizona/registers.h>
+#include "arizona.h"
#include "wm_adsp.h"
#define adsp_crit(_dsp, fmt, ...) \
@@ -193,17 +194,25 @@ static void wm_adsp_buf_free(struct list_head *list)
#define WM_ADSP_NUM_FW 4
+#define WM_ADSP_FW_MBC_VSS 0
+#define WM_ADSP_FW_TX 1
+#define WM_ADSP_FW_TX_SPK 2
+#define WM_ADSP_FW_RX_ANC 3
+
static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
- "MBC/VSS", "Tx", "Tx Speaker", "Rx ANC"
+ [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
+ [WM_ADSP_FW_TX] = "Tx",
+ [WM_ADSP_FW_TX_SPK] = "Tx Speaker",
+ [WM_ADSP_FW_RX_ANC] = "Rx ANC",
};
static struct {
const char *file;
} wm_adsp_fw[WM_ADSP_NUM_FW] = {
- { .file = "mbc-vss" },
- { .file = "tx" },
- { .file = "tx-spk" },
- { .file = "rx-anc" },
+ [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
+ [WM_ADSP_FW_TX] = { .file = "tx" },
+ [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" },
+ [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" },
};
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
@@ -246,17 +255,52 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
};
-const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
+const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
+ SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
+ wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
+ wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
+ wm_adsp_fw_get, wm_adsp_fw_put),
+};
+EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
+
+#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
+static const struct soc_enum wm_adsp2_rate_enum[] = {
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
+ ARIZONA_DSP1_RATE_SHIFT, 0xf,
+ ARIZONA_RATE_ENUM_SIZE,
+ arizona_rate_text, arizona_rate_val),
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
+ ARIZONA_DSP1_RATE_SHIFT, 0xf,
+ ARIZONA_RATE_ENUM_SIZE,
+ arizona_rate_text, arizona_rate_val),
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+ ARIZONA_DSP1_RATE_SHIFT, 0xf,
+ ARIZONA_RATE_ENUM_SIZE,
+ arizona_rate_text, arizona_rate_val),
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+ ARIZONA_DSP1_RATE_SHIFT, 0xf,
+ ARIZONA_RATE_ENUM_SIZE,
+ arizona_rate_text, arizona_rate_val),
+};
+
+const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
wm_adsp_fw_get, wm_adsp_fw_put),
+ SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
};
-EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
+EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
+#endif
static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
int type)
@@ -549,13 +593,30 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
buf_size = sizeof(adsp1_id);
algs = be32_to_cpu(adsp1_id.algs);
+ dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
- be32_to_cpu(adsp1_id.fw.id),
+ dsp->fw_id,
(be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(adsp1_id.fw.ver) & 0xff,
algs);
+ region = kzalloc(sizeof(*region), GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+ region->type = WMFW_ADSP1_ZM;
+ region->alg = be32_to_cpu(adsp1_id.fw.id);
+ region->base = be32_to_cpu(adsp1_id.zm);
+ list_add_tail(&region->list, &dsp->alg_regions);
+
+ region = kzalloc(sizeof(*region), GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+ region->type = WMFW_ADSP1_DM;
+ region->alg = be32_to_cpu(adsp1_id.fw.id);
+ region->base = be32_to_cpu(adsp1_id.dm);
+ list_add_tail(&region->list, &dsp->alg_regions);
+
pos = sizeof(adsp1_id) / 2;
term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
break;
@@ -573,13 +634,38 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
buf_size = sizeof(adsp2_id);
algs = be32_to_cpu(adsp2_id.algs);
+ dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
- be32_to_cpu(adsp2_id.fw.id),
+ dsp->fw_id,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(adsp2_id.fw.ver) & 0xff,
algs);
+ region = kzalloc(sizeof(*region), GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+ region->type = WMFW_ADSP2_XM;
+ region->alg = be32_to_cpu(adsp2_id.fw.id);
+ region->base = be32_to_cpu(adsp2_id.xm);
+ list_add_tail(&region->list, &dsp->alg_regions);
+
+ region = kzalloc(sizeof(*region), GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+ region->type = WMFW_ADSP2_YM;
+ region->alg = be32_to_cpu(adsp2_id.fw.id);
+ region->base = be32_to_cpu(adsp2_id.ym);
+ list_add_tail(&region->list, &dsp->alg_regions);
+
+ region = kzalloc(sizeof(*region), GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+ region->type = WMFW_ADSP2_ZM;
+ region->alg = be32_to_cpu(adsp2_id.fw.id);
+ region->base = be32_to_cpu(adsp2_id.zm);
+ list_add_tail(&region->list, &dsp->alg_regions);
+
pos = sizeof(adsp2_id) / 2;
term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
break;
@@ -781,8 +867,24 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
case (WMFW_INFO_TEXT << 8):
break;
case (WMFW_ABSOLUTE << 8):
- region_name = "register";
- reg = offset;
+ /*
+ * Old files may use this for global
+ * coefficients.
+ */
+ if (le32_to_cpu(blk->id) == dsp->fw_id &&
+ offset == 0) {
+ region_name = "global coefficients";
+ mem = wm_adsp_find_region(dsp, type);
+ if (!mem) {
+ adsp_err(dsp, "No ZM\n");
+ break;
+ }
+ reg = wm_adsp_region_to_reg(mem, 0);
+
+ } else {
+ region_name = "register";
+ reg = offset;
+ }
break;
case WMFW_ADSP1_DM:
@@ -828,7 +930,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
&buf_list);
if (!buf) {
adsp_err(dsp, "Out of memory\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_fw;
}
adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
@@ -865,7 +968,7 @@ out_fw:
wm_adsp_buf_free(&buf_list);
out:
kfree(file);
- return 0;
+ return ret;
}
int wm_adsp1_init(struct wm_adsp *adsp)