#define ADSP2_WDMA_CONFIG_2 0x31
#define ADSP2_RDMA_CONFIG_1 0x34
+#define ADSP2_SCRATCH0 0x40
+#define ADSP2_SCRATCH1 0x41
+#define ADSP2_SCRATCH2 0x42
+#define ADSP2_SCRATCH3 0x43
+
/*
* ADSP2 Control
*/
size_t len;
unsigned int set:1;
struct snd_kcontrol *kcontrol;
+ unsigned int flags;
};
static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
}
}
+static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
+{
+ u16 scratch[4];
+ int ret;
+
+ ret = regmap_raw_read(dsp->regmap, dsp->base + ADSP2_SCRATCH0,
+ scratch, sizeof(scratch));
+ if (ret) {
+ adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret);
+ return;
+ }
+
+ adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
+ be16_to_cpu(scratch[0]),
+ be16_to_cpu(scratch[1]),
+ be16_to_cpu(scratch[2]),
+ be16_to_cpu(scratch[3]));
+}
+
static int wm_coeff_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
char *p = ucontrol->value.bytes.data;
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) {
+ if (ctl->enabled)
+ return wm_coeff_read_control(ctl, p, ctl->len);
+ else
+ return -EPERM;
+ }
+
memcpy(p, ctl->cache, ctl->len);
+
return 0;
}
kcontrol->put = wm_coeff_put;
kcontrol->private_value = (unsigned long)ctl;
+ if (ctl->flags) {
+ if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE)
+ kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+ if (ctl->flags & WMFW_CTL_FLAG_READABLE)
+ kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ;
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+ kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+ }
+
ret = snd_soc_add_card_controls(dsp->card,
kcontrol, 1);
if (ret < 0)
list_for_each_entry(ctl, &dsp->ctl_list, list) {
if (!ctl->enabled || ctl->set)
continue;
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+ continue;
+
ret = wm_coeff_read_control(ctl,
ctl->cache,
ctl->len);
list_for_each_entry(ctl, &dsp->ctl_list, list) {
if (!ctl->enabled)
continue;
- if (ctl->set) {
+ if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
ret = wm_coeff_write_control(ctl,
ctl->cache,
ctl->len);
static int wm_adsp_create_control(struct wm_adsp *dsp,
const struct wm_adsp_alg_region *alg_region,
unsigned int offset, unsigned int len,
- const char *subname, unsigned int subname_len)
+ const char *subname, unsigned int subname_len,
+ unsigned int flags)
{
struct wm_coeff_ctl *ctl;
struct wmfw_ctl_work *ctl_work;
char *region_name;
int ret;
+ if (flags & WMFW_CTL_FLAG_SYS)
+ return 0;
+
switch (alg_region->type) {
case WMFW_ADSP1_PM:
region_name = "PM";
ctl->ops.xput = wm_coeff_put;
ctl->dsp = dsp;
+ ctl->flags = flags;
ctl->offset = offset;
if (len > 512) {
adsp_warn(dsp, "Truncating control %s from %d\n",
coeff_blk.offset,
coeff_blk.len,
coeff_blk.name,
- coeff_blk.name_len);
+ coeff_blk.name_len,
+ coeff_blk.flags);
if (ret < 0)
adsp_err(dsp, "Failed to create control: %.*s, %d\n",
coeff_blk.name_len, coeff_blk.name, ret);
len -= be32_to_cpu(adsp1_alg[i].dm);
len *= 4;
wm_adsp_create_control(dsp, alg_region, 0,
- len, NULL, 0);
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id));
len -= be32_to_cpu(adsp1_alg[i].zm);
len *= 4;
wm_adsp_create_control(dsp, alg_region, 0,
- len, NULL, 0);
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id));
len -= be32_to_cpu(adsp2_alg[i].xm);
len *= 4;
wm_adsp_create_control(dsp, alg_region, 0,
- len, NULL, 0);
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id));
len -= be32_to_cpu(adsp2_alg[i].ym);
len *= 4;
wm_adsp_create_control(dsp, alg_region, 0,
- len, NULL, 0);
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id));
len -= be32_to_cpu(adsp2_alg[i].zm);
len *= 4;
wm_adsp_create_control(dsp, alg_region, 0,
- len, NULL, 0);
+ len, NULL, 0, 0);
} else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id));
return;
}
- if (dsp->dvfs) {
- ret = regmap_read(dsp->regmap,
- dsp->base + ADSP2_CLOCKING, &val);
- if (ret != 0) {
- adsp_err(dsp, "Failed to read clocking: %d\n", ret);
- return;
- }
-
- if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
- ret = regulator_enable(dsp->dvfs);
- if (ret != 0) {
- adsp_err(dsp,
- "Failed to enable supply: %d\n",
- ret);
- return;
- }
-
- ret = regulator_set_voltage(dsp->dvfs,
- 1800000,
- 1800000);
- if (ret != 0) {
- adsp_err(dsp,
- "Failed to raise supply: %d\n",
- ret);
- return;
- }
- }
- }
-
ret = wm_adsp2_ena(dsp);
if (ret != 0)
return;
break;
case SND_SOC_DAPM_PRE_PMD:
+ /* Log firmware state, it can be useful for analysis */
+ wm_adsp2_show_fw_status(dsp);
+
dsp->running = false;
regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
- if (dsp->dvfs) {
- ret = regulator_set_voltage(dsp->dvfs, 1200000,
- 1800000);
- if (ret != 0)
- adsp_warn(dsp,
- "Failed to lower supply: %d\n",
- ret);
-
- ret = regulator_disable(dsp->dvfs);
- if (ret != 0)
- adsp_err(dsp,
- "Failed to enable supply: %d\n",
- ret);
- }
-
list_for_each_entry(ctl, &dsp->ctl_list, list)
ctl->enabled = 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_event);
-int wm_adsp2_init(struct wm_adsp *dsp, bool dvfs)
+int wm_adsp2_init(struct wm_adsp *dsp)
{
int ret;
INIT_LIST_HEAD(&dsp->ctl_list);
INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
- if (dvfs) {
- dsp->dvfs = devm_regulator_get(dsp->dev, "DCVDD");
- if (IS_ERR(dsp->dvfs)) {
- ret = PTR_ERR(dsp->dvfs);
- adsp_err(dsp, "Failed to get DCVDD: %d\n", ret);
- return ret;
- }
-
- ret = regulator_enable(dsp->dvfs);
- if (ret != 0) {
- adsp_err(dsp, "Failed to enable DCVDD: %d\n", ret);
- return ret;
- }
-
- ret = regulator_set_voltage(dsp->dvfs, 1200000, 1800000);
- if (ret != 0) {
- adsp_err(dsp, "Failed to initialise DVFS: %d\n", ret);
- return ret;
- }
-
- ret = regulator_disable(dsp->dvfs);
- if (ret != 0) {
- adsp_err(dsp, "Failed to disable DCVDD: %d\n", ret);
- return ret;
- }
- }
-
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_init);