Merge remote-tracking branch 'asoc/topic/rt5670' into asoc-next
[deliverable/linux.git] / sound / soc / codecs / wm_adsp.c
index 9283d08de3d90f72f9344759f7d65c12b0547fb1..b62ffd0c133ea1f02868f774d12f9ecc70a64357 100644 (file)
 #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
  */
@@ -229,16 +234,18 @@ struct wm_coeff_ctl_ops {
 
 struct wm_coeff_ctl {
        const char *name;
+       const char *fw_name;
        struct wm_adsp_alg_region alg_region;
        struct wm_coeff_ctl_ops ops;
        struct wm_adsp *dsp;
-       void *private;
        unsigned int enabled:1;
        struct list_head list;
        void *cache;
+       unsigned int offset;
        size_t len;
        unsigned int set:1;
        struct snd_kcontrol *kcontrol;
+       unsigned int flags;
 };
 
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
@@ -362,6 +369,25 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
        }
 }
 
+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)
 {
@@ -389,7 +415,7 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl,
                return -EINVAL;
        }
 
-       reg = ctl->alg_region.base;
+       reg = ctl->alg_region.base + ctl->offset;
        reg = wm_adsp_region_to_reg(mem, reg);
 
        scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
@@ -443,7 +469,7 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl,
                return -EINVAL;
        }
 
-       reg = ctl->alg_region.base;
+       reg = ctl->alg_region.base + ctl->offset;
        reg = wm_adsp_region_to_reg(mem, reg);
 
        scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
@@ -471,7 +497,15 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol,
        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;
 }
 
@@ -500,6 +534,15 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
        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)
@@ -510,8 +553,6 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
        ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card,
                                                  ctl->name);
 
-       list_add(&ctl->list, &dsp->ctl_list);
-
        return 0;
 
 err_kcontrol:
@@ -519,6 +560,358 @@ err_kcontrol:
        return ret;
 }
 
+static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
+{
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       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);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int wm_coeff_sync_controls(struct wm_adsp *dsp)
+{
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       list_for_each_entry(ctl, &dsp->ctl_list, list) {
+               if (!ctl->enabled)
+                       continue;
+               if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) {
+                       ret = wm_coeff_write_control(ctl,
+                                                    ctl->cache,
+                                                    ctl->len);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void wm_adsp_ctl_work(struct work_struct *work)
+{
+       struct wmfw_ctl_work *ctl_work = container_of(work,
+                                                     struct wmfw_ctl_work,
+                                                     work);
+
+       wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
+       kfree(ctl_work);
+}
+
+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,
+                                 unsigned int flags)
+{
+       struct wm_coeff_ctl *ctl;
+       struct wmfw_ctl_work *ctl_work;
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char *region_name;
+       int ret;
+
+       if (flags & WMFW_CTL_FLAG_SYS)
+               return 0;
+
+       switch (alg_region->type) {
+       case WMFW_ADSP1_PM:
+               region_name = "PM";
+               break;
+       case WMFW_ADSP1_DM:
+               region_name = "DM";
+               break;
+       case WMFW_ADSP2_XM:
+               region_name = "XM";
+               break;
+       case WMFW_ADSP2_YM:
+               region_name = "YM";
+               break;
+       case WMFW_ADSP1_ZM:
+               region_name = "ZM";
+               break;
+       default:
+               adsp_err(dsp, "Unknown region type: %d\n", alg_region->type);
+               return -EINVAL;
+       }
+
+       switch (dsp->fw_ver) {
+       case 0:
+       case 1:
+               snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
+                        dsp->num, region_name, alg_region->alg);
+               break;
+       default:
+               ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+                               "DSP%d%c %.12s %x", dsp->num, *region_name,
+                               wm_adsp_fw_text[dsp->fw], alg_region->alg);
+
+               /* Truncate the subname from the start if it is too long */
+               if (subname) {
+                       int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
+                       int skip = 0;
+
+                       if (subname_len > avail)
+                               skip = subname_len - avail;
+
+                       snprintf(name + ret,
+                                SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s",
+                                subname_len - skip, subname + skip);
+               }
+               break;
+       }
+
+       list_for_each_entry(ctl, &dsp->ctl_list,
+                           list) {
+               if (!strcmp(ctl->name, name)) {
+                       if (!ctl->enabled)
+                               ctl->enabled = 1;
+                       return 0;
+               }
+       }
+
+       ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
+       if (!ctl)
+               return -ENOMEM;
+       ctl->fw_name = wm_adsp_fw_text[dsp->fw];
+       ctl->alg_region = *alg_region;
+       ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
+       if (!ctl->name) {
+               ret = -ENOMEM;
+               goto err_ctl;
+       }
+       ctl->enabled = 1;
+       ctl->set = 0;
+       ctl->ops.xget = wm_coeff_get;
+       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",
+                         ctl->name, len);
+               len = 512;
+       }
+       ctl->len = len;
+       ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
+       if (!ctl->cache) {
+               ret = -ENOMEM;
+               goto err_ctl_name;
+       }
+
+       list_add(&ctl->list, &dsp->ctl_list);
+
+       ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
+       if (!ctl_work) {
+               ret = -ENOMEM;
+               goto err_ctl_cache;
+       }
+
+       ctl_work->dsp = dsp;
+       ctl_work->ctl = ctl;
+       INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
+       schedule_work(&ctl_work->work);
+
+       return 0;
+
+err_ctl_cache:
+       kfree(ctl->cache);
+err_ctl_name:
+       kfree(ctl->name);
+err_ctl:
+       kfree(ctl);
+
+       return ret;
+}
+
+struct wm_coeff_parsed_alg {
+       int id;
+       const u8 *name;
+       int name_len;
+       int ncoeff;
+};
+
+struct wm_coeff_parsed_coeff {
+       int offset;
+       int mem_type;
+       const u8 *name;
+       int name_len;
+       int ctl_type;
+       int flags;
+       int len;
+};
+
+static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
+{
+       int length;
+
+       switch (bytes) {
+       case 1:
+               length = **pos;
+               break;
+       case 2:
+               length = le16_to_cpu(*((__le16 *)*pos));
+               break;
+       default:
+               return 0;
+       }
+
+       if (str)
+               *str = *pos + bytes;
+
+       *pos += ((length + bytes) + 3) & ~0x03;
+
+       return length;
+}
+
+static int wm_coeff_parse_int(int bytes, const u8 **pos)
+{
+       int val = 0;
+
+       switch (bytes) {
+       case 2:
+               val = le16_to_cpu(*((__le16 *)*pos));
+               break;
+       case 4:
+               val = le32_to_cpu(*((__le32 *)*pos));
+               break;
+       default:
+               break;
+       }
+
+       *pos += bytes;
+
+       return val;
+}
+
+static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data,
+                                     struct wm_coeff_parsed_alg *blk)
+{
+       const struct wmfw_adsp_alg_data *raw;
+
+       switch (dsp->fw_ver) {
+       case 0:
+       case 1:
+               raw = (const struct wmfw_adsp_alg_data *)*data;
+               *data = raw->data;
+
+               blk->id = le32_to_cpu(raw->id);
+               blk->name = raw->name;
+               blk->name_len = strlen(raw->name);
+               blk->ncoeff = le32_to_cpu(raw->ncoeff);
+               break;
+       default:
+               blk->id = wm_coeff_parse_int(sizeof(raw->id), data);
+               blk->name_len = wm_coeff_parse_string(sizeof(u8), data,
+                                                     &blk->name);
+               wm_coeff_parse_string(sizeof(u16), data, NULL);
+               blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data);
+               break;
+       }
+
+       adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id);
+       adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name);
+       adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff);
+}
+
+static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data,
+                                       struct wm_coeff_parsed_coeff *blk)
+{
+       const struct wmfw_adsp_coeff_data *raw;
+       const u8 *tmp;
+       int length;
+
+       switch (dsp->fw_ver) {
+       case 0:
+       case 1:
+               raw = (const struct wmfw_adsp_coeff_data *)*data;
+               *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size);
+
+               blk->offset = le16_to_cpu(raw->hdr.offset);
+               blk->mem_type = le16_to_cpu(raw->hdr.type);
+               blk->name = raw->name;
+               blk->name_len = strlen(raw->name);
+               blk->ctl_type = le16_to_cpu(raw->ctl_type);
+               blk->flags = le16_to_cpu(raw->flags);
+               blk->len = le32_to_cpu(raw->len);
+               break;
+       default:
+               tmp = *data;
+               blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp);
+               blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp);
+               length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp);
+               blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp,
+                                                     &blk->name);
+               wm_coeff_parse_string(sizeof(u8), &tmp, NULL);
+               wm_coeff_parse_string(sizeof(u16), &tmp, NULL);
+               blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp);
+               blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp);
+               blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp);
+
+               *data = *data + sizeof(raw->hdr) + length;
+               break;
+       }
+
+       adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type);
+       adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset);
+       adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name);
+       adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags);
+       adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type);
+       adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len);
+}
+
+static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
+                              const struct wmfw_region *region)
+{
+       struct wm_adsp_alg_region alg_region = {};
+       struct wm_coeff_parsed_alg alg_blk;
+       struct wm_coeff_parsed_coeff coeff_blk;
+       const u8 *data = region->data;
+       int i, ret;
+
+       wm_coeff_parse_alg(dsp, &data, &alg_blk);
+       for (i = 0; i < alg_blk.ncoeff; i++) {
+               wm_coeff_parse_coeff(dsp, &data, &coeff_blk);
+
+               switch (coeff_blk.ctl_type) {
+               case SNDRV_CTL_ELEM_TYPE_BYTES:
+                       break;
+               default:
+                       adsp_err(dsp, "Unknown control type: %d\n",
+                                coeff_blk.ctl_type);
+                       return -EINVAL;
+               }
+
+               alg_region.type = coeff_blk.mem_type;
+               alg_region.alg = alg_blk.id;
+
+               ret = wm_adsp_create_control(dsp, &alg_region,
+                                            coeff_blk.offset,
+                                            coeff_blk.len,
+                                            coeff_blk.name,
+                                            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);
+       }
+
+       return 0;
+}
+
 static int wm_adsp_load(struct wm_adsp *dsp)
 {
        LIST_HEAD(buf_list);
@@ -567,12 +960,22 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                goto out_fw;
        }
 
-       if (header->ver != 0) {
+       switch (header->ver) {
+       case 0:
+               adsp_warn(dsp, "%s: Depreciated file format %d\n",
+                         file, header->ver);
+               break;
+       case 1:
+       case 2:
+               break;
+       default:
                adsp_err(dsp, "%s: unknown file format %d\n",
                         file, header->ver);
                goto out_fw;
        }
+
        adsp_info(dsp, "Firmware version: %d\n", header->ver);
+       dsp->fw_ver = header->ver;
 
        if (header->core != dsp->type) {
                adsp_err(dsp, "%s: invalid core %d != %d\n",
@@ -637,6 +1040,12 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                        text = kzalloc(le32_to_cpu(region->len) + 1,
                                       GFP_KERNEL);
                        break;
+               case WMFW_ALGORITHM_DATA:
+                       region_name = "Algorithm";
+                       ret = wm_adsp_parse_coeff(dsp, region);
+                       if (ret != 0)
+                               goto out_fw;
+                       break;
                case WMFW_INFO_TEXT:
                        region_name = "Information";
                        text = kzalloc(le32_to_cpu(region->len) + 1,
@@ -729,144 +1138,18 @@ out:
        return ret;
 }
 
-static int wm_coeff_init_control_caches(struct wm_adsp *dsp)
-{
-       struct wm_coeff_ctl *ctl;
-       int ret;
-
-       list_for_each_entry(ctl, &dsp->ctl_list, list) {
-               if (!ctl->enabled || ctl->set)
-                       continue;
-               ret = wm_coeff_read_control(ctl,
-                                           ctl->cache,
-                                           ctl->len);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static int wm_coeff_sync_controls(struct wm_adsp *dsp)
+static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
+                                 const struct wm_adsp_alg_region *alg_region)
 {
        struct wm_coeff_ctl *ctl;
-       int ret;
 
        list_for_each_entry(ctl, &dsp->ctl_list, list) {
-               if (!ctl->enabled)
-                       continue;
-               if (ctl->set) {
-                       ret = wm_coeff_write_control(ctl,
-                                                    ctl->cache,
-                                                    ctl->len);
-                       if (ret < 0)
-                               return ret;
+               if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
+                   alg_region->alg == ctl->alg_region.alg &&
+                   alg_region->type == ctl->alg_region.type) {
+                       ctl->alg_region.base = alg_region->base;
                }
        }
-
-       return 0;
-}
-
-static void wm_adsp_ctl_work(struct work_struct *work)
-{
-       struct wmfw_ctl_work *ctl_work = container_of(work,
-                                                     struct wmfw_ctl_work,
-                                                     work);
-
-       wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl);
-       kfree(ctl_work);
-}
-
-static int wm_adsp_create_control(struct wm_adsp *dsp,
-                                 const struct wm_adsp_alg_region *alg_region,
-                                 unsigned int len)
-{
-       struct wm_coeff_ctl *ctl;
-       struct wmfw_ctl_work *ctl_work;
-       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       char *region_name;
-       int ret;
-
-       switch (alg_region->type) {
-       case WMFW_ADSP1_PM:
-               region_name = "PM";
-               break;
-       case WMFW_ADSP1_DM:
-               region_name = "DM";
-               break;
-       case WMFW_ADSP2_XM:
-               region_name = "XM";
-               break;
-       case WMFW_ADSP2_YM:
-               region_name = "YM";
-               break;
-       case WMFW_ADSP1_ZM:
-               region_name = "ZM";
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
-                dsp->num, region_name, alg_region->alg);
-
-       list_for_each_entry(ctl, &dsp->ctl_list,
-                           list) {
-               if (!strcmp(ctl->name, name)) {
-                       if (!ctl->enabled)
-                               ctl->enabled = 1;
-                       return 0;
-               }
-       }
-
-       ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
-       if (!ctl)
-               return -ENOMEM;
-       ctl->alg_region = *alg_region;
-       ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
-       if (!ctl->name) {
-               ret = -ENOMEM;
-               goto err_ctl;
-       }
-       ctl->enabled = 1;
-       ctl->set = 0;
-       ctl->ops.xget = wm_coeff_get;
-       ctl->ops.xput = wm_coeff_put;
-       ctl->dsp = dsp;
-
-       if (len > 512) {
-               adsp_warn(dsp, "Truncating control %s from %d\n",
-                         ctl->name, len);
-               len = 512;
-       }
-       ctl->len = len;
-       ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
-       if (!ctl->cache) {
-               ret = -ENOMEM;
-               goto err_ctl_name;
-       }
-
-       ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
-       if (!ctl_work) {
-               ret = -ENOMEM;
-               goto err_ctl_cache;
-       }
-
-       ctl_work->dsp = dsp;
-       ctl_work->ctl = ctl;
-       INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
-       schedule_work(&ctl_work->work);
-
-       return 0;
-
-err_ctl_cache:
-       kfree(ctl->cache);
-err_ctl_name:
-       kfree(ctl->name);
-err_ctl:
-       kfree(ctl);
-
-       return ret;
 }
 
 static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
@@ -929,6 +1212,9 @@ static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp,
 
        list_add_tail(&alg_region->list, &dsp->alg_regions);
 
+       if (dsp->fw_ver > 0)
+               wm_adsp_ctl_fixup_base(dsp, alg_region);
+
        return alg_region;
 }
 
@@ -996,14 +1282,17 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
                        ret = PTR_ERR(alg_region);
                        goto out;
                }
-               if (i + 1 < n_algs) {
-                       len = be32_to_cpu(adsp1_alg[i + 1].dm);
-                       len -= be32_to_cpu(adsp1_alg[i].dm);
-                       len *= 4;
-                       wm_adsp_create_control(dsp, alg_region, len);
-               } else {
-                       adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
-                                 be32_to_cpu(adsp1_alg[i].alg.id));
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp1_alg[i + 1].dm);
+                               len -= be32_to_cpu(adsp1_alg[i].dm);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 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));
+                       }
                }
 
                alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
@@ -1013,14 +1302,17 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
                        ret = PTR_ERR(alg_region);
                        goto out;
                }
-               if (i + 1 < n_algs) {
-                       len = be32_to_cpu(adsp1_alg[i + 1].zm);
-                       len -= be32_to_cpu(adsp1_alg[i].zm);
-                       len *= 4;
-                       wm_adsp_create_control(dsp, alg_region, len);
-               } else {
-                       adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
-                                 be32_to_cpu(adsp1_alg[i].alg.id));
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp1_alg[i + 1].zm);
+                               len -= be32_to_cpu(adsp1_alg[i].zm);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 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));
+                       }
                }
        }
 
@@ -1100,14 +1392,17 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                        ret = PTR_ERR(alg_region);
                        goto out;
                }
-               if (i + 1 < n_algs) {
-                       len = be32_to_cpu(adsp2_alg[i + 1].xm);
-                       len -= be32_to_cpu(adsp2_alg[i].xm);
-                       len *= 4;
-                       wm_adsp_create_control(dsp, alg_region, len);
-               } else {
-                       adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
-                                 be32_to_cpu(adsp2_alg[i].alg.id));
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp2_alg[i + 1].xm);
+                               len -= be32_to_cpu(adsp2_alg[i].xm);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 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));
+                       }
                }
 
                alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM,
@@ -1117,14 +1412,17 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                        ret = PTR_ERR(alg_region);
                        goto out;
                }
-               if (i + 1 < n_algs) {
-                       len = be32_to_cpu(adsp2_alg[i + 1].ym);
-                       len -= be32_to_cpu(adsp2_alg[i].ym);
-                       len *= 4;
-                       wm_adsp_create_control(dsp, alg_region, len);
-               } else {
-                       adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
-                                 be32_to_cpu(adsp2_alg[i].alg.id));
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp2_alg[i + 1].ym);
+                               len -= be32_to_cpu(adsp2_alg[i].ym);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 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));
+                       }
                }
 
                alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM,
@@ -1134,14 +1432,17 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
                        ret = PTR_ERR(alg_region);
                        goto out;
                }
-               if (i + 1 < n_algs) {
-                       len = be32_to_cpu(adsp2_alg[i + 1].zm);
-                       len -= be32_to_cpu(adsp2_alg[i].zm);
-                       len *= 4;
-                       wm_adsp_create_control(dsp, alg_region, len);
-               } else {
-                       adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
-                                 be32_to_cpu(adsp2_alg[i].alg.id));
+               if (dsp->fw_ver == 0) {
+                       if (i + 1 < n_algs) {
+                               len = be32_to_cpu(adsp2_alg[i + 1].zm);
+                               len -= be32_to_cpu(adsp2_alg[i].zm);
+                               len *= 4;
+                               wm_adsp_create_control(dsp, alg_region, 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));
+                       }
                }
        }
 
@@ -1510,35 +1811,6 @@ static void wm_adsp2_boot_work(struct work_struct *work)
                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;
@@ -1621,6 +1893,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                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,
@@ -1632,21 +1907,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                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;
 
@@ -1673,7 +1933,7 @@ err:
 }
 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;
 
@@ -1692,33 +1952,6 @@ int wm_adsp2_init(struct wm_adsp *dsp, bool dvfs)
        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);
This page took 0.043308 seconds and 5 git commands to generate.