Merge tag 'asoc-fix-v5.18-rc7' of https://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / sound / soc / codecs / wm_adsp.c
index 5a57bb04a0aeb3ea5204f0ce26ee91d3f169c93e..7973a75cac059fbef263c6d47baea23a4349550c 100644 (file)
@@ -180,7 +180,7 @@ struct wm_adsp_compr {
 
 #define WM_ADSP_MIN_FRAGMENTS          1
 #define WM_ADSP_MAX_FRAGMENTS          256
-#define WM_ADSP_MIN_FRAGMENT_SIZE      (64 * CS_DSP_DATA_WORD_SIZE)
+#define WM_ADSP_MIN_FRAGMENT_SIZE      (16 * CS_DSP_DATA_WORD_SIZE)
 #define WM_ADSP_MAX_FRAGMENT_SIZE      (4096 * CS_DSP_DATA_WORD_SIZE)
 
 #define WM_ADSP_ALG_XM_STRUCT_MAGIC    0x49aec7
@@ -296,7 +296,12 @@ static const struct {
                .num_caps = ARRAY_SIZE(trace_caps),
                .caps = trace_caps,
        },
-       [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" },
+       [WM_ADSP_FW_SPK_PROT] = {
+               .file = "spk-prot",
+               .compr_direction = SND_COMPRESS_CAPTURE,
+               .num_caps = ARRAY_SIZE(trace_caps),
+               .caps = trace_caps,
+       },
        [WM_ADSP_FW_SPK_CALI] = { .file = "spk-cali" },
        [WM_ADSP_FW_SPK_DIAG] = { .file = "spk-diag" },
        [WM_ADSP_FW_MISC] =     { .file = "misc" },
@@ -744,21 +749,48 @@ static void wm_adsp_release_firmware_files(struct wm_adsp *dsp,
 }
 
 static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
-                                        const struct firmware **firmware,
-                                        char **filename,
-                                        char *suffix)
+                                        const struct firmware **firmware, char **filename,
+                                        const char *dir, const char *system_name,
+                                        const char *asoc_component_prefix,
+                                        const char *filetype)
 {
        struct cs_dsp *cs_dsp = &dsp->cs_dsp;
+       char *s, c;
        int ret = 0;
 
-       *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", dsp->part, dsp->fwf_name,
-                             wm_adsp_fw[dsp->fw].file, suffix);
+       if (system_name && asoc_component_prefix)
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s-%s.%s", dir, dsp->part,
+                                     dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name,
+                                     asoc_component_prefix, filetype);
+       else if (system_name)
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s-%s.%s", dir, dsp->part,
+                                     dsp->fwf_name, wm_adsp_fw[dsp->fw].file, system_name,
+                                     filetype);
+       else
+               *filename = kasprintf(GFP_KERNEL, "%s%s-%s-%s.%s", dir, dsp->part, dsp->fwf_name,
+                                     wm_adsp_fw[dsp->fw].file, filetype);
+
        if (*filename == NULL)
                return -ENOMEM;
 
-       ret = request_firmware(firmware, *filename, cs_dsp->dev);
+       /*
+        * Make sure that filename is lower-case and any non alpha-numeric
+        * characters except full stop and forward slash are replaced with
+        * hyphens.
+        */
+       s = *filename;
+       while (*s) {
+               c = *s;
+               if (isalnum(c))
+                       *s = tolower(c);
+               else if ((c != '.') && (c != '/'))
+                       *s = '-';
+               s++;
+       }
+
+       ret = firmware_request_nowarn(firmware, *filename, cs_dsp->dev);
        if (ret != 0) {
-               adsp_err(dsp, "Failed to request '%s'\n", *filename);
+               adsp_dbg(dsp, "Failed to request '%s'\n", *filename);
                kfree(*filename);
                *filename = NULL;
        }
@@ -766,21 +798,69 @@ static int wm_adsp_request_firmware_file(struct wm_adsp *dsp,
        return ret;
 }
 
+static const char *cirrus_dir = "cirrus/";
 static int wm_adsp_request_firmware_files(struct wm_adsp *dsp,
                                          const struct firmware **wmfw_firmware,
                                          char **wmfw_filename,
                                          const struct firmware **coeff_firmware,
                                          char **coeff_filename)
 {
+       const char *system_name = dsp->system_name;
+       const char *asoc_component_prefix = dsp->component->name_prefix;
        int ret = 0;
 
-       ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename, "wmfw");
-       if (ret != 0)
-               return ret;
+       if (system_name && asoc_component_prefix) {
+               if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
+                                                  cirrus_dir, system_name,
+                                                  asoc_component_prefix, "wmfw")) {
+                       adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename);
+                       wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+                                                     cirrus_dir, system_name,
+                                                     asoc_component_prefix, "bin");
+                       return 0;
+               }
+       }
 
-       wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename, "bin");
+       if (system_name) {
+               if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
+                                                  cirrus_dir, system_name,
+                                                  NULL, "wmfw")) {
+                       adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename);
+                       if (asoc_component_prefix)
+                               wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+                                                             cirrus_dir, system_name,
+                                                             asoc_component_prefix, "bin");
+
+                       if (!*coeff_firmware)
+                               wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+                                                             cirrus_dir, system_name,
+                                                             NULL, "bin");
+                       return 0;
+               }
+       }
 
-       return 0;
+       if (!wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
+                                          "", NULL, NULL, "wmfw")) {
+               adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename);
+               wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+                                             "", NULL, NULL, "bin");
+               return 0;
+       }
+
+       ret = wm_adsp_request_firmware_file(dsp, wmfw_firmware, wmfw_filename,
+                                           cirrus_dir, NULL, NULL, "wmfw");
+       if (!ret) {
+               adsp_dbg(dsp, "Found '%s'\n", *wmfw_filename);
+               wm_adsp_request_firmware_file(dsp, coeff_firmware, coeff_filename,
+                                             cirrus_dir, NULL, NULL, "bin");
+               return 0;
+       }
+
+       adsp_err(dsp, "Failed to request firmware <%s>%s-%s-%s<-%s<%s>>.wmfw\n",
+                cirrus_dir, dsp->part, dsp->fwf_name, wm_adsp_fw[dsp->fw].file,
+                system_name, asoc_component_prefix);
+
+       return -ENOENT;
 }
 
 static int wm_adsp_common_init(struct wm_adsp *dsp)
@@ -1373,8 +1453,6 @@ static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
 
        wm_adsp_buffer_clear(buf);
 
-       list_add_tail(&buf->list, &dsp->buffer_list);
-
        return buf;
 }
 
@@ -1391,10 +1469,6 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
                return -EINVAL;
        }
 
-       buf = wm_adsp_buffer_alloc(dsp);
-       if (!buf)
-               return -ENOMEM;
-
        xmalg = dsp->sys_config_size / sizeof(__be32);
 
        addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
@@ -1405,12 +1479,16 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
        if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
                return -ENODEV;
 
+       buf = wm_adsp_buffer_alloc(dsp);
+       if (!buf)
+               return -ENOMEM;
+
        addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
        for (i = 0; i < 5; ++i) {
                ret = cs_dsp_read_data_word(&dsp->cs_dsp, WMFW_ADSP2_XM, addr,
                                            &buf->host_buf_ptr);
                if (ret < 0)
-                       return ret;
+                       goto err;
 
                if (buf->host_buf_ptr)
                        break;
@@ -1418,18 +1496,27 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
                usleep_range(1000, 2000);
        }
 
-       if (!buf->host_buf_ptr)
-               return -EIO;
+       if (!buf->host_buf_ptr) {
+               ret = -EIO;
+               goto err;
+       }
 
        buf->host_buf_mem_type = WMFW_ADSP2_XM;
 
        ret = wm_adsp_buffer_populate(buf);
        if (ret < 0)
-               return ret;
+               goto err;
+
+       list_add_tail(&buf->list, &dsp->buffer_list);
 
        compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
 
        return 0;
+
+err:
+       kfree(buf);
+
+       return ret;
 }
 
 static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
@@ -1437,7 +1524,7 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
        struct wm_adsp_host_buf_coeff_v1 coeff_v1;
        struct wm_adsp_compr_buf *buf;
        struct wm_adsp *dsp = container_of(cs_ctl->dsp, struct wm_adsp, cs_dsp);
-       unsigned int version;
+       unsigned int version = 0;
        int ret, i;
 
        for (i = 0; i < 5; ++i) {
@@ -1466,16 +1553,14 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
 
        ret = wm_adsp_buffer_populate(buf);
        if (ret < 0)
-               return ret;
+               goto err;
 
        /*
         * v0 host_buffer coefficients didn't have versioning, so if the
         * control is one word, assume version 0.
         */
-       if (cs_ctl->len == 4) {
-               compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr);
-               return 0;
-       }
+       if (cs_ctl->len == 4)
+               goto done;
 
        version = be32_to_cpu(coeff_v1.versions) & HOST_BUF_COEFF_COMPAT_VER_MASK;
        version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
@@ -1484,7 +1569,8 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
                adsp_err(dsp,
                         "Host buffer coeff ver %u > supported version %u\n",
                         version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
 
        cs_dsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name));
@@ -1492,10 +1578,18 @@ static int wm_adsp_buffer_parse_coeff(struct cs_dsp_coeff_ctl *cs_ctl)
        buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", dsp->part,
                              (char *)&coeff_v1.name);
 
+done:
+       list_add_tail(&buf->list, &dsp->buffer_list);
+
        compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
                  buf->host_buf_ptr, version);
 
        return version;
+
+err:
+       kfree(buf);
+
+       return ret;
 }
 
 static int wm_adsp_buffer_init(struct wm_adsp *dsp)
@@ -1523,10 +1617,8 @@ static int wm_adsp_buffer_init(struct wm_adsp *dsp)
        if (list_empty(&dsp->buffer_list)) {
                /* Fall back to legacy support */
                ret = wm_adsp_buffer_parse_legacy(dsp);
-               if (ret) {
-                       adsp_err(dsp, "Failed to parse legacy: %d\n", ret);
-                       goto error;
-               }
+               if (ret)
+                       adsp_warn(dsp, "Failed to parse legacy: %d\n", ret);
        }
 
        return 0;