Merge branch 'asoc-4.18' into asoc-4.19 wmadsp dep
[muen/linux.git] / sound / soc / codecs / wm_adsp.c
index 08dc82770273272895fb2e32b9a92a9b7117797e..1c12c78dbcce841962d57cfa0ea6bc46970cc413 100644 (file)
@@ -418,7 +418,7 @@ static const struct wm_adsp_fw_caps ctrl_caps[] = {
        {
                .id = SND_AUDIOCODEC_BESPOKE,
                .desc = {
-                       .max_ch = 1,
+                       .max_ch = 8,
                        .sample_rates = { 16000 },
                        .num_sample_rates = 1,
                        .formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -627,22 +627,21 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
        if (!root)
                goto err;
 
-       if (!debugfs_create_bool("booted", S_IRUGO, root, &dsp->booted))
+       if (!debugfs_create_bool("booted", 0444, root, &dsp->booted))
                goto err;
 
-       if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running))
+       if (!debugfs_create_bool("running", 0444, root, &dsp->running))
                goto err;
 
-       if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id))
+       if (!debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id))
                goto err;
 
-       if (!debugfs_create_x32("fw_version", S_IRUGO, root,
-                               &dsp->fw_id_version))
+       if (!debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version))
                goto err;
 
        for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) {
                if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name,
-                                        S_IRUGO, root, dsp,
+                                        0444, root, dsp,
                                         &wm_adsp_debugfs_fops[i].fops))
                        goto err;
        }
@@ -685,8 +684,8 @@ static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
 }
 #endif
 
-static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
+int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
+                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -696,9 +695,10 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
 
-static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
+int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
+                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -722,8 +722,9 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
 
-static const struct soc_enum wm_adsp_fw_enum[] = {
+const struct soc_enum wm_adsp_fw_enum[] = {
        SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
        SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
        SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
@@ -732,24 +733,7 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
        SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
        SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 };
-
-const struct snd_kcontrol_new wm_adsp_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),
-       SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP5 Firmware", wm_adsp_fw_enum[4],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP6 Firmware", wm_adsp_fw_enum[5],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-       SOC_ENUM_EXT("DSP7 Firmware", wm_adsp_fw_enum[6],
-                    wm_adsp_fw_get, wm_adsp_fw_put),
-};
-EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
+EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
 
 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
                                                        int type)
@@ -1344,6 +1328,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
                        int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
                        int skip = 0;
 
+                       if (dsp->component->name_prefix)
+                               avail -= strlen(dsp->component->name_prefix) + 1;
+
                        if (subname_len > avail)
                                skip = subname_len - avail;
 
@@ -1605,6 +1592,15 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
                        if (ret)
                                return -EINVAL;
                        break;
+               case WMFW_CTL_TYPE_HOST_BUFFER:
+                       ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
+                                               WMFW_CTL_FLAG_SYS |
+                                               WMFW_CTL_FLAG_VOLATILE |
+                                               WMFW_CTL_FLAG_READABLE,
+                                               0);
+                       if (ret)
+                               return -EINVAL;
+                       break;
                default:
                        adsp_err(dsp, "Unknown control type: %d\n",
                                 coeff_blk.ctl_type);
@@ -1872,9 +1868,11 @@ static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
 }
 
 static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
+                              const struct wm_adsp_region *mem,
                               unsigned int pos, unsigned int len)
 {
        void *alg;
+       unsigned int reg;
        int ret;
        __be32 val;
 
@@ -1889,7 +1887,9 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
        }
 
        /* Read the terminator first to validate the length */
-       ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
+       reg = wm_adsp_region_to_reg(mem, pos + len);
+
+       ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
        if (ret != 0) {
                adsp_err(dsp, "Failed to read algorithm list end: %d\n",
                        ret);
@@ -1898,13 +1898,18 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
 
        if (be32_to_cpu(val) != 0xbedead)
                adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
-                         pos + len, be32_to_cpu(val));
+                         reg, be32_to_cpu(val));
 
-       alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
+       /* Convert length from DSP words to bytes */
+       len *= sizeof(u32);
+
+       alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
        if (!alg)
                return ERR_PTR(-ENOMEM);
 
-       ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
+       reg = wm_adsp_region_to_reg(mem, pos);
+
+       ret = regmap_raw_read(dsp->regmap, reg, alg, len);
        if (ret != 0) {
                adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
                kfree(alg);
@@ -2003,10 +2008,11 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
        if (IS_ERR(alg_region))
                return PTR_ERR(alg_region);
 
-       pos = sizeof(adsp1_id) / 2;
-       len = (sizeof(*adsp1_alg) * n_algs) / 2;
+       /* Calculate offset and length in DSP words */
+       pos = sizeof(adsp1_id) / sizeof(u32);
+       len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
 
-       adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+       adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
        if (IS_ERR(adsp1_alg))
                return PTR_ERR(adsp1_alg);
 
@@ -2114,10 +2120,11 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
        if (IS_ERR(alg_region))
                return PTR_ERR(alg_region);
 
-       pos = sizeof(adsp2_id) / 2;
-       len = (sizeof(*adsp2_alg) * n_algs) / 2;
+       /* Calculate offset and length in DSP words */
+       pos = sizeof(adsp2_id) / sizeof(u32);
+       len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
 
-       adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+       adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
        if (IS_ERR(adsp2_alg))
                return PTR_ERR(adsp2_alg);
 
@@ -2868,9 +2875,7 @@ int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *comp
 
        dsp->component = component;
 
-       return snd_soc_add_component_controls(component,
-                                         &wm_adsp_fw_controls[dsp->num - 1],
-                                         1);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
 
@@ -3193,7 +3198,7 @@ static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
                                       buf->host_buf_ptr + field_offset, data);
 }
 
-static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
 {
        struct wm_adsp_alg_region *alg_region;
        struct wm_adsp *dsp = buf->dsp;
@@ -3232,6 +3237,61 @@ static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
        return 0;
 }
 
+static struct wm_coeff_ctl *
+wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf)
+{
+       struct wm_adsp *dsp = buf->dsp;
+       struct wm_coeff_ctl *ctl;
+
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
+               if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
+                       continue;
+
+               if (!ctl->enabled)
+                       continue;
+
+               return ctl;
+       }
+
+       return NULL;
+}
+
+static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+{
+       struct wm_adsp *dsp = buf->dsp;
+       struct wm_coeff_ctl *ctl;
+       unsigned int reg;
+       u32 val;
+       int i, ret;
+
+       ctl = wm_adsp_find_host_buffer_ctrl(buf);
+       if (!ctl)
+               return wm_adsp_legacy_host_buf_addr(buf);
+
+       ret = wm_coeff_base_reg(ctl, &reg);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < 5; ++i) {
+               ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
+               if (ret < 0)
+                       return ret;
+
+               if (val)
+                       break;
+
+               usleep_range(1000, 2000);
+       }
+
+       if (!val)
+               return -EIO;
+
+       buf->host_buf_ptr = be32_to_cpu(val);
+       adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+       return 0;
+}
+
 static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
 {
        const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;