Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 4d3ec29..9b8bb7b 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* wm_adsp.c -- Wolfson ADSP support
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/ctype.h>
@@ -46,6 +43,13 @@
#define adsp_dbg(_dsp, fmt, ...) \
dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
+#define compr_err(_obj, fmt, ...) \
+ adsp_err(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
+ ##__VA_ARGS__)
+#define compr_dbg(_obj, fmt, ...) \
+ adsp_dbg(_obj->dsp, "%s: " fmt, _obj->name ? _obj->name : "legacy", \
+ ##__VA_ARGS__)
+
#define ADSP1_CONTROL_1 0x00
#define ADSP1_CONTROL_2 0x02
#define ADSP1_CONTROL_3 0x03
@@ -220,6 +224,89 @@
*/
#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001
+/*
+ * HALO system info
+ */
+#define HALO_AHBM_WINDOW_DEBUG_0 0x02040
+#define HALO_AHBM_WINDOW_DEBUG_1 0x02044
+
+/*
+ * HALO core
+ */
+#define HALO_SCRATCH1 0x005c0
+#define HALO_SCRATCH2 0x005c8
+#define HALO_SCRATCH3 0x005d0
+#define HALO_SCRATCH4 0x005d8
+#define HALO_CCM_CORE_CONTROL 0x41000
+#define HALO_CORE_SOFT_RESET 0x00010
+#define HALO_WDT_CONTROL 0x47000
+
+/*
+ * HALO MPU banks
+ */
+#define HALO_MPU_XMEM_ACCESS_0 0x43000
+#define HALO_MPU_YMEM_ACCESS_0 0x43004
+#define HALO_MPU_WINDOW_ACCESS_0 0x43008
+#define HALO_MPU_XREG_ACCESS_0 0x4300C
+#define HALO_MPU_YREG_ACCESS_0 0x43014
+#define HALO_MPU_XMEM_ACCESS_1 0x43018
+#define HALO_MPU_YMEM_ACCESS_1 0x4301C
+#define HALO_MPU_WINDOW_ACCESS_1 0x43020
+#define HALO_MPU_XREG_ACCESS_1 0x43024
+#define HALO_MPU_YREG_ACCESS_1 0x4302C
+#define HALO_MPU_XMEM_ACCESS_2 0x43030
+#define HALO_MPU_YMEM_ACCESS_2 0x43034
+#define HALO_MPU_WINDOW_ACCESS_2 0x43038
+#define HALO_MPU_XREG_ACCESS_2 0x4303C
+#define HALO_MPU_YREG_ACCESS_2 0x43044
+#define HALO_MPU_XMEM_ACCESS_3 0x43048
+#define HALO_MPU_YMEM_ACCESS_3 0x4304C
+#define HALO_MPU_WINDOW_ACCESS_3 0x43050
+#define HALO_MPU_XREG_ACCESS_3 0x43054
+#define HALO_MPU_YREG_ACCESS_3 0x4305C
+#define HALO_MPU_XM_VIO_ADDR 0x43100
+#define HALO_MPU_XM_VIO_STATUS 0x43104
+#define HALO_MPU_YM_VIO_ADDR 0x43108
+#define HALO_MPU_YM_VIO_STATUS 0x4310C
+#define HALO_MPU_PM_VIO_ADDR 0x43110
+#define HALO_MPU_PM_VIO_STATUS 0x43114
+#define HALO_MPU_LOCK_CONFIG 0x43140
+
+/*
+ * HALO_AHBM_WINDOW_DEBUG_1
+ */
+#define HALO_AHBM_CORE_ERR_ADDR_MASK 0x0fffff00
+#define HALO_AHBM_CORE_ERR_ADDR_SHIFT 8
+#define HALO_AHBM_FLAGS_ERR_MASK 0x000000ff
+
+/*
+ * HALO_CCM_CORE_CONTROL
+ */
+#define HALO_CORE_EN 0x00000001
+
+/*
+ * HALO_CORE_SOFT_RESET
+ */
+#define HALO_CORE_SOFT_RESET_MASK 0x00000001
+
+/*
+ * HALO_WDT_CONTROL
+ */
+#define HALO_WDT_EN_MASK 0x00000001
+
+/*
+ * HALO_MPU_?M_VIO_STATUS
+ */
+#define HALO_MPU_VIO_STS_MASK 0x007e0000
+#define HALO_MPU_VIO_STS_SHIFT 17
+#define HALO_MPU_VIO_ERR_WR_MASK 0x00008000
+#define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff
+#define HALO_MPU_VIO_ERR_SRC_SHIFT 0
+
+static struct wm_adsp_ops wm_adsp1_ops;
+static struct wm_adsp_ops wm_adsp2_ops[];
+static struct wm_adsp_ops wm_halo_ops;
+
struct wm_adsp_buf {
struct list_head list;
void *buf;
@@ -299,6 +386,12 @@
__be32 build_job_number;
};
+struct wm_halo_system_config_xm_hdr {
+ __be32 halo_heartbeat;
+ __be32 build_job_name[3];
+ __be32 build_job_number;
+};
+
struct wm_adsp_alg_xm_struct {
__be32 magic;
__be32 smoothing;
@@ -310,13 +403,19 @@
__be64 smoothed_power;
};
+struct wm_adsp_host_buf_coeff_v1 {
+ __be32 host_buf_ptr; /* Host buffer pointer */
+ __be32 versions; /* Version numbers */
+ __be32 name[4]; /* The buffer name */
+};
+
struct wm_adsp_buffer {
- __be32 X_buf_base; /* XM base addr of first X area */
- __be32 X_buf_size; /* Size of 1st X area in words */
- __be32 X_buf_base2; /* XM base addr of 2nd X area */
- __be32 X_buf_brk; /* Total X size in words */
- __be32 Y_buf_base; /* YM base addr of Y area */
- __be32 wrap; /* Total size X and Y in words */
+ __be32 buf1_base; /* Base addr of first buffer area */
+ __be32 buf1_size; /* Size of buf1 area in DSP words */
+ __be32 buf2_base; /* Base addr of 2nd buffer area */
+ __be32 buf1_buf2_size; /* Size of buf1+buf2 in DSP words */
+ __be32 buf3_base; /* Base addr of buf3 area */
+ __be32 buf_total_size; /* Size of buf1+buf2+buf3 in DSP words */
__be32 high_water_mark; /* Point at which IRQ is asserted */
__be32 irq_count; /* bits 1-31 count IRQ assertions */
__be32 irq_ack; /* acked IRQ count, bit 0 enables IRQ */
@@ -334,6 +433,7 @@
struct wm_adsp_compr;
struct wm_adsp_compr_buf {
+ struct list_head list;
struct wm_adsp *dsp;
struct wm_adsp_compr *compr;
@@ -344,9 +444,13 @@
u32 irq_count;
int read_index;
int avail;
+ int host_buf_mem_type;
+
+ char *name;
};
struct wm_adsp_compr {
+ struct list_head list;
struct wm_adsp *dsp;
struct wm_adsp_compr_buf *buf;
@@ -357,6 +461,8 @@
unsigned int copied_total;
unsigned int sample_rate;
+
+ const char *name;
};
#define WM_ADSP_DATA_WORD_SIZE 3
@@ -374,6 +480,11 @@
#define ALG_XM_FIELD(field) \
(offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32))
+#define HOST_BUF_COEFF_SUPPORTED_COMPAT_VER 1
+
+#define HOST_BUF_COEFF_COMPAT_VER_MASK 0xFF00
+#define HOST_BUF_COEFF_COMPAT_VER_SHIFT 8
+
static int wm_adsp_buffer_init(struct wm_adsp *dsp);
static int wm_adsp_buffer_free(struct wm_adsp *dsp);
@@ -393,18 +504,18 @@
static const struct wm_adsp_buffer_region_def default_regions[] = {
{
.mem_type = WMFW_ADSP2_XM,
- .base_offset = HOST_BUFFER_FIELD(X_buf_base),
- .size_offset = HOST_BUFFER_FIELD(X_buf_size),
+ .base_offset = HOST_BUFFER_FIELD(buf1_base),
+ .size_offset = HOST_BUFFER_FIELD(buf1_size),
},
{
.mem_type = WMFW_ADSP2_XM,
- .base_offset = HOST_BUFFER_FIELD(X_buf_base2),
- .size_offset = HOST_BUFFER_FIELD(X_buf_brk),
+ .base_offset = HOST_BUFFER_FIELD(buf2_base),
+ .size_offset = HOST_BUFFER_FIELD(buf1_buf2_size),
},
{
.mem_type = WMFW_ADSP2_YM,
- .base_offset = HOST_BUFFER_FIELD(Y_buf_base),
- .size_offset = HOST_BUFFER_FIELD(wrap),
+ .base_offset = HOST_BUFFER_FIELD(buf3_base),
+ .size_offset = HOST_BUFFER_FIELD(buf_total_size),
},
};
@@ -507,12 +618,18 @@
switch (type) {
case WMFW_ADSP1_PM:
return "PM";
+ case WMFW_HALO_PM_PACKED:
+ return "PM_PACKED";
case WMFW_ADSP1_DM:
return "DM";
case WMFW_ADSP2_XM:
return "XM";
+ case WMFW_HALO_XM_PACKED:
+ return "XM_PACKED";
case WMFW_ADSP2_YM:
return "YM";
+ case WMFW_HALO_YM_PACKED:
+ return "YM_PACKED";
case WMFW_ADSP1_ZM:
return "ZM";
default:
@@ -611,41 +728,18 @@
struct dentry *root = NULL;
int i;
- if (!component->debugfs_root) {
- adsp_err(dsp, "No codec debugfs root\n");
- goto err;
- }
-
root = debugfs_create_dir(dsp->name, component->debugfs_root);
- if (!root)
- goto err;
+ debugfs_create_bool("booted", 0444, root, &dsp->booted);
+ debugfs_create_bool("running", 0444, root, &dsp->running);
+ debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id);
+ debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version);
- if (!debugfs_create_bool("booted", 0444, root, &dsp->booted))
- goto err;
-
- if (!debugfs_create_bool("running", 0444, root, &dsp->running))
- goto err;
-
- if (!debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id))
- goto err;
-
- 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,
- 0444, root, dsp,
- &wm_adsp_debugfs_fops[i].fops))
- goto err;
- }
+ for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i)
+ debugfs_create_file(wm_adsp_debugfs_fops[i].name, 0444, root,
+ dsp, &wm_adsp_debugfs_fops[i].fops);
dsp->debugfs_root = root;
- return;
-
-err:
- debugfs_remove_recursive(root);
- adsp_err(dsp, "Failed to create debugfs\n");
}
static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp)
@@ -707,7 +801,7 @@
mutex_lock(&dsp[e->shift_l].pwr_lock);
- if (dsp[e->shift_l].booted || dsp[e->shift_l].compr)
+ if (dsp[e->shift_l].booted || !list_empty(&dsp[e->shift_l].compr_list))
ret = -EBUSY;
else
dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
@@ -744,17 +838,12 @@
static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *mem,
unsigned int offset)
{
- if (WARN_ON(!mem))
- return offset;
switch (mem->type) {
case WMFW_ADSP1_PM:
return mem->base + (offset * 3);
case WMFW_ADSP1_DM:
- return mem->base + (offset * 2);
case WMFW_ADSP2_XM:
- return mem->base + (offset * 2);
case WMFW_ADSP2_YM:
- return mem->base + (offset * 2);
case WMFW_ADSP1_ZM:
return mem->base + (offset * 2);
default:
@@ -763,49 +852,72 @@
}
}
-static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
+static unsigned int wm_halo_region_to_reg(struct wm_adsp_region const *mem,
+ unsigned int offset)
{
- unsigned int scratch[4];
- unsigned int addr = dsp->base + ADSP2_SCRATCH0;
+ switch (mem->type) {
+ case WMFW_ADSP2_XM:
+ case WMFW_ADSP2_YM:
+ return mem->base + (offset * 4);
+ case WMFW_HALO_XM_PACKED:
+ case WMFW_HALO_YM_PACKED:
+ return (mem->base + (offset * 3)) & ~0x3;
+ case WMFW_HALO_PM_PACKED:
+ return mem->base + (offset * 5);
+ default:
+ WARN(1, "Unknown memory region type");
+ return offset;
+ }
+}
+
+static void wm_adsp_read_fw_status(struct wm_adsp *dsp,
+ int noffs, unsigned int *offs)
+{
unsigned int i;
int ret;
- for (i = 0; i < ARRAY_SIZE(scratch); ++i) {
- ret = regmap_read(dsp->regmap, addr + i, &scratch[i]);
+ for (i = 0; i < noffs; ++i) {
+ ret = regmap_read(dsp->regmap, dsp->base + offs[i], &offs[i]);
if (ret) {
adsp_err(dsp, "Failed to read SCRATCH%u: %d\n", i, ret);
return;
}
}
+}
+
+static void wm_adsp2_show_fw_status(struct wm_adsp *dsp)
+{
+ unsigned int offs[] = {
+ ADSP2_SCRATCH0, ADSP2_SCRATCH1, ADSP2_SCRATCH2, ADSP2_SCRATCH3,
+ };
+
+ wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
- scratch[0], scratch[1], scratch[2], scratch[3]);
+ offs[0], offs[1], offs[2], offs[3]);
}
static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp)
{
- unsigned int scratch[2];
- int ret;
+ unsigned int offs[] = { ADSP2V2_SCRATCH0_1, ADSP2V2_SCRATCH2_3 };
- ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1,
- &scratch[0]);
- if (ret) {
- adsp_err(dsp, "Failed to read SCRATCH0_1: %d\n", ret);
- return;
- }
-
- ret = regmap_read(dsp->regmap, dsp->base + ADSP2V2_SCRATCH2_3,
- &scratch[1]);
- if (ret) {
- adsp_err(dsp, "Failed to read SCRATCH2_3: %d\n", ret);
- return;
- }
+ wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
- scratch[0] & 0xFFFF,
- scratch[0] >> 16,
- scratch[1] & 0xFFFF,
- scratch[1] >> 16);
+ offs[0] & 0xFFFF, offs[0] >> 16,
+ offs[1] & 0xFFFF, offs[1] >> 16);
+}
+
+static void wm_halo_show_fw_status(struct wm_adsp *dsp)
+{
+ unsigned int offs[] = {
+ HALO_SCRATCH1, HALO_SCRATCH2, HALO_SCRATCH3, HALO_SCRATCH4,
+ };
+
+ wm_adsp_read_fw_status(dsp, ARRAY_SIZE(offs), offs);
+
+ adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n",
+ offs[0], offs[1], offs[2], offs[3]);
}
static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
@@ -826,7 +938,7 @@
return -EINVAL;
}
- *reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset);
+ *reg = dsp->ops->region_to_reg(mem, ctl->alg_region.base + ctl->offset);
return 0;
}
@@ -1147,8 +1259,7 @@
}
if (in) {
- if (in & WMFW_CTL_FLAG_READABLE)
- out |= rd;
+ out |= rd;
if (in & WMFW_CTL_FLAG_WRITEABLE)
out |= wr;
if (in & WMFW_CTL_FLAG_VOLATILE)
@@ -1314,28 +1425,33 @@
case 1:
snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
dsp->name, region_name, alg_region->alg);
+ subname = NULL; /* don't append subname */
break;
- default:
+ case 2:
ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
"%s%c %.12s %x", dsp->name, *region_name,
wm_adsp_fw_text[dsp->fw], alg_region->alg);
+ break;
+ default:
+ ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+ "%s %.12s %x", dsp->name,
+ wm_adsp_fw_text[dsp->fw], alg_region->alg);
+ break;
+ }
+
+ if (subname) {
+ 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;
/* 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;
- if (dsp->component->name_prefix)
- avail -= strlen(dsp->component->name_prefix) + 1;
-
- 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;
+ snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
+ " %.*s", subname_len - skip, subname + skip);
}
list_for_each_entry(ctl, &dsp->ctl_list, list) {
@@ -1622,6 +1738,62 @@
return 0;
}
+static unsigned int wm_adsp1_parse_sizes(struct wm_adsp *dsp,
+ const char * const file,
+ unsigned int pos,
+ const struct firmware *firmware)
+{
+ const struct wmfw_adsp1_sizes *adsp1_sizes;
+
+ adsp1_sizes = (void *)&firmware->data[pos];
+
+ adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file,
+ le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm),
+ le32_to_cpu(adsp1_sizes->zm));
+
+ return pos + sizeof(*adsp1_sizes);
+}
+
+static unsigned int wm_adsp2_parse_sizes(struct wm_adsp *dsp,
+ const char * const file,
+ unsigned int pos,
+ const struct firmware *firmware)
+{
+ const struct wmfw_adsp2_sizes *adsp2_sizes;
+
+ adsp2_sizes = (void *)&firmware->data[pos];
+
+ adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file,
+ le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym),
+ le32_to_cpu(adsp2_sizes->pm), le32_to_cpu(adsp2_sizes->zm));
+
+ return pos + sizeof(*adsp2_sizes);
+}
+
+static bool wm_adsp_validate_version(struct wm_adsp *dsp, unsigned int version)
+{
+ switch (version) {
+ case 0:
+ adsp_warn(dsp, "Deprecated file format %d\n", version);
+ return true;
+ case 1:
+ case 2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool wm_halo_validate_version(struct wm_adsp *dsp, unsigned int version)
+{
+ switch (version) {
+ case 3:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int wm_adsp_load(struct wm_adsp *dsp)
{
LIST_HEAD(buf_list);
@@ -1630,7 +1802,6 @@
unsigned int pos = 0;
const struct wmfw_header *header;
const struct wmfw_adsp1_sizes *adsp1_sizes;
- const struct wmfw_adsp2_sizes *adsp2_sizes;
const struct wmfw_footer *footer;
const struct wmfw_region *region;
const struct wm_adsp_region *mem;
@@ -1639,7 +1810,7 @@
struct wm_adsp_buf *buf;
unsigned int reg;
int regions = 0;
- int ret, offset, type, sizes;
+ int ret, offset, type;
file = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (file == NULL)
@@ -1670,15 +1841,7 @@
goto out_fw;
}
- switch (header->ver) {
- case 0:
- adsp_warn(dsp, "%s: Depreciated file format %d\n",
- file, header->ver);
- break;
- case 1:
- case 2:
- break;
- default:
+ if (!dsp->ops->validate_version(dsp, header->ver)) {
adsp_err(dsp, "%s: unknown file format %d\n",
file, header->ver);
goto out_fw;
@@ -1693,39 +1856,13 @@
goto out_fw;
}
- switch (dsp->type) {
- case WMFW_ADSP1:
- pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
- adsp1_sizes = (void *)&(header[1]);
- footer = (void *)&(adsp1_sizes[1]);
- sizes = sizeof(*adsp1_sizes);
+ pos = sizeof(*header);
+ pos = dsp->ops->parse_sizes(dsp, file, pos, firmware);
- adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n",
- file, le32_to_cpu(adsp1_sizes->dm),
- le32_to_cpu(adsp1_sizes->pm),
- le32_to_cpu(adsp1_sizes->zm));
- break;
+ footer = (void *)&firmware->data[pos];
+ pos += sizeof(*footer);
- case WMFW_ADSP2:
- pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer);
- adsp2_sizes = (void *)&(header[1]);
- footer = (void *)&(adsp2_sizes[1]);
- sizes = sizeof(*adsp2_sizes);
-
- adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n",
- file, le32_to_cpu(adsp2_sizes->xm),
- le32_to_cpu(adsp2_sizes->ym),
- le32_to_cpu(adsp2_sizes->pm),
- le32_to_cpu(adsp2_sizes->zm));
- break;
-
- default:
- WARN(1, "Unknown DSP type");
- goto out_fw;
- }
-
- if (le32_to_cpu(header->len) != sizeof(*header) +
- sizes + sizeof(*footer)) {
+ if (le32_to_cpu(header->len) != pos) {
adsp_err(dsp, "%s: unexpected header length %d\n",
file, le32_to_cpu(header->len));
goto out_fw;
@@ -1742,7 +1879,6 @@
text = NULL;
offset = le32_to_cpu(region->offset) & 0xffffff;
type = be32_to_cpu(region->type) & 0xff;
- mem = wm_adsp_find_region(dsp, type);
switch (type) {
case WMFW_NAME_TEXT:
@@ -1770,8 +1906,17 @@
case WMFW_ADSP2_XM:
case WMFW_ADSP2_YM:
case WMFW_ADSP1_ZM:
+ case WMFW_HALO_PM_PACKED:
+ case WMFW_HALO_XM_PACKED:
+ case WMFW_HALO_YM_PACKED:
+ mem = wm_adsp_find_region(dsp, type);
+ if (!mem) {
+ adsp_err(dsp, "No region of type: %x\n", type);
+ goto out_fw;
+ }
+
region_name = wm_adsp_mem_region_name(type);
- reg = wm_adsp_region_to_reg(mem, offset);
+ reg = dsp->ops->region_to_reg(mem, offset);
break;
default:
adsp_warn(dsp,
@@ -1884,7 +2029,7 @@
}
/* Read the terminator first to validate the length */
- reg = wm_adsp_region_to_reg(mem, pos + len);
+ reg = dsp->ops->region_to_reg(mem, pos + len);
ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
if (ret != 0) {
@@ -1904,7 +2049,7 @@
if (!alg)
return ERR_PTR(-ENOMEM);
- reg = wm_adsp_region_to_reg(mem, pos);
+ reg = dsp->ops->region_to_reg(mem, pos);
ret = regmap_raw_read(dsp->regmap, reg, alg, len);
if (ret != 0) {
@@ -1964,6 +2109,47 @@
}
}
+static void wmfw_parse_id_header(struct wm_adsp *dsp,
+ struct wmfw_id_hdr *fw, int nalgs)
+{
+ dsp->fw_id = be32_to_cpu(fw->id);
+ dsp->fw_id_version = be32_to_cpu(fw->ver);
+
+ adsp_info(dsp, "Firmware: %x v%d.%d.%d, %d algorithms\n",
+ dsp->fw_id, (dsp->fw_id_version & 0xff0000) >> 16,
+ (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
+ nalgs);
+}
+
+static void wmfw_v3_parse_id_header(struct wm_adsp *dsp,
+ struct wmfw_v3_id_hdr *fw, int nalgs)
+{
+ dsp->fw_id = be32_to_cpu(fw->id);
+ dsp->fw_id_version = be32_to_cpu(fw->ver);
+ dsp->fw_vendor_id = be32_to_cpu(fw->vendor_id);
+
+ adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %d algorithms\n",
+ dsp->fw_id, dsp->fw_vendor_id,
+ (dsp->fw_id_version & 0xff0000) >> 16,
+ (dsp->fw_id_version & 0xff00) >> 8, dsp->fw_id_version & 0xff,
+ nalgs);
+}
+
+static int wm_adsp_create_regions(struct wm_adsp *dsp, __be32 id, int nregions,
+ int *type, __be32 *base)
+{
+ struct wm_adsp_alg_region *alg_region;
+ int i;
+
+ for (i = 0; i < nregions; i++) {
+ alg_region = wm_adsp_create_region(dsp, type[i], id, base[i]);
+ if (IS_ERR(alg_region))
+ return PTR_ERR(alg_region);
+ }
+
+ return 0;
+}
+
static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
{
struct wmfw_adsp1_id_hdr adsp1_id;
@@ -1987,13 +2173,8 @@
}
n_algs = be32_to_cpu(adsp1_id.n_algs);
- dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
- adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
- 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,
- n_algs);
+
+ wmfw_parse_id_header(dsp, &adsp1_id.fw, n_algs);
alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM,
adsp1_id.fw.id, adsp1_id.zm);
@@ -2093,14 +2274,8 @@
}
n_algs = be32_to_cpu(adsp2_id.n_algs);
- dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
- dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver);
- adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
- dsp->fw_id,
- (dsp->fw_id_version & 0xff0000) >> 16,
- (dsp->fw_id_version & 0xff00) >> 8,
- dsp->fw_id_version & 0xff,
- n_algs);
+
+ wmfw_parse_id_header(dsp, &adsp2_id.fw, n_algs);
alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM,
adsp2_id.fw.id, adsp2_id.xm);
@@ -2205,6 +2380,78 @@
return ret;
}
+static int wm_halo_create_regions(struct wm_adsp *dsp, __be32 id,
+ __be32 xm_base, __be32 ym_base)
+{
+ int types[] = {
+ WMFW_ADSP2_XM, WMFW_HALO_XM_PACKED,
+ WMFW_ADSP2_YM, WMFW_HALO_YM_PACKED
+ };
+ __be32 bases[] = { xm_base, xm_base, ym_base, ym_base };
+
+ return wm_adsp_create_regions(dsp, id, ARRAY_SIZE(types), types, bases);
+}
+
+static int wm_halo_setup_algs(struct wm_adsp *dsp)
+{
+ struct wmfw_halo_id_hdr halo_id;
+ struct wmfw_halo_alg_hdr *halo_alg;
+ const struct wm_adsp_region *mem;
+ unsigned int pos, len;
+ size_t n_algs;
+ int i, ret;
+
+ mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
+ if (WARN_ON(!mem))
+ return -EINVAL;
+
+ ret = regmap_raw_read(dsp->regmap, mem->base, &halo_id,
+ sizeof(halo_id));
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to read algorithm info: %d\n",
+ ret);
+ return ret;
+ }
+
+ n_algs = be32_to_cpu(halo_id.n_algs);
+
+ wmfw_v3_parse_id_header(dsp, &halo_id.fw, n_algs);
+
+ ret = wm_halo_create_regions(dsp, halo_id.fw.id,
+ halo_id.xm_base, halo_id.ym_base);
+ if (ret)
+ return ret;
+
+ /* Calculate offset and length in DSP words */
+ pos = sizeof(halo_id) / sizeof(u32);
+ len = (sizeof(*halo_alg) * n_algs) / sizeof(u32);
+
+ halo_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
+ if (IS_ERR(halo_alg))
+ return PTR_ERR(halo_alg);
+
+ for (i = 0; i < n_algs; i++) {
+ adsp_info(dsp,
+ "%d: ID %x v%d.%d.%d XM@%x YM@%x\n",
+ i, be32_to_cpu(halo_alg[i].alg.id),
+ (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16,
+ (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8,
+ be32_to_cpu(halo_alg[i].alg.ver) & 0xff,
+ be32_to_cpu(halo_alg[i].xm_base),
+ be32_to_cpu(halo_alg[i].ym_base));
+
+ ret = wm_halo_create_regions(dsp, halo_alg[i].alg.id,
+ halo_alg[i].xm_base,
+ halo_alg[i].ym_base);
+ if (ret)
+ goto out;
+ }
+
+out:
+ kfree(halo_alg);
+ return ret;
+}
+
static int wm_adsp_load_coeff(struct wm_adsp *dsp)
{
LIST_HEAD(buf_list);
@@ -2299,7 +2546,7 @@
adsp_err(dsp, "No ZM\n");
break;
}
- reg = wm_adsp_region_to_reg(mem, 0);
+ reg = dsp->ops->region_to_reg(mem, 0);
} else {
region_name = "register";
@@ -2311,6 +2558,9 @@
case WMFW_ADSP1_ZM:
case WMFW_ADSP2_XM:
case WMFW_ADSP2_YM:
+ case WMFW_HALO_XM_PACKED:
+ case WMFW_HALO_YM_PACKED:
+ case WMFW_HALO_PM_PACKED:
adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n",
file, blocks, le32_to_cpu(blk->len),
type, le32_to_cpu(blk->id));
@@ -2325,7 +2575,7 @@
le32_to_cpu(blk->id));
if (alg_region) {
reg = alg_region->base;
- reg = wm_adsp_region_to_reg(mem, reg);
+ reg = dsp->ops->region_to_reg(mem, reg);
reg += offset;
} else {
adsp_err(dsp, "No %x for algorithm %x\n",
@@ -2419,7 +2669,7 @@
return 0;
}
-int wm_adsp1_init(struct wm_adsp *dsp)
+static int wm_adsp_common_init(struct wm_adsp *dsp)
{
int ret;
@@ -2428,11 +2678,21 @@
return ret;
INIT_LIST_HEAD(&dsp->alg_regions);
+ INIT_LIST_HEAD(&dsp->ctl_list);
+ INIT_LIST_HEAD(&dsp->compr_list);
+ INIT_LIST_HEAD(&dsp->buffer_list);
mutex_init(&dsp->pwr_lock);
return 0;
}
+
+int wm_adsp1_init(struct wm_adsp *dsp)
+{
+ dsp->ops = &wm_adsp1_ops;
+
+ return wm_adsp_common_init(dsp);
+}
EXPORT_SYMBOL_GPL(wm_adsp1_init);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
@@ -2550,23 +2810,11 @@
}
EXPORT_SYMBOL_GPL(wm_adsp1_event);
-static int wm_adsp2_ena(struct wm_adsp *dsp)
+static int wm_adsp2v2_enable_core(struct wm_adsp *dsp)
{
unsigned int val;
int ret, count;
- switch (dsp->rev) {
- case 0:
- ret = regmap_update_bits_async(dsp->regmap,
- dsp->base + ADSP2_CONTROL,
- ADSP2_SYS_ENA, ADSP2_SYS_ENA);
- if (ret != 0)
- return ret;
- break;
- default:
- break;
- }
-
/* Wait for the RAM to start, should be near instantaneous */
for (count = 0; count < 10; ++count) {
ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val);
@@ -2589,7 +2837,78 @@
return 0;
}
-static void wm_adsp2_boot_work(struct work_struct *work)
+static int wm_adsp2_enable_core(struct wm_adsp *dsp)
+{
+ int ret;
+
+ ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_SYS_ENA, ADSP2_SYS_ENA);
+ if (ret != 0)
+ return ret;
+
+ return wm_adsp2v2_enable_core(dsp);
+}
+
+static int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
+{
+ struct regmap *regmap = dsp->regmap;
+ unsigned int code0, code1, lock_reg;
+
+ if (!(lock_regions & WM_ADSP2_REGION_ALL))
+ return 0;
+
+ lock_regions &= WM_ADSP2_REGION_ALL;
+ lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
+
+ while (lock_regions) {
+ code0 = code1 = 0;
+ if (lock_regions & BIT(0)) {
+ code0 = ADSP2_LOCK_CODE_0;
+ code1 = ADSP2_LOCK_CODE_1;
+ }
+ if (lock_regions & BIT(1)) {
+ code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
+ code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
+ }
+ regmap_write(regmap, lock_reg, code0);
+ regmap_write(regmap, lock_reg, code1);
+ lock_regions >>= 2;
+ lock_reg += 2;
+ }
+
+ return 0;
+}
+
+static int wm_adsp2_enable_memory(struct wm_adsp *dsp)
+{
+ return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_MEM_ENA, ADSP2_MEM_ENA);
+}
+
+static void wm_adsp2_disable_memory(struct wm_adsp *dsp)
+{
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_MEM_ENA, 0);
+}
+
+static void wm_adsp2_disable_core(struct wm_adsp *dsp)
+{
+ regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
+ regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
+ regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0);
+
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_SYS_ENA, 0);
+}
+
+static void wm_adsp2v2_disable_core(struct wm_adsp *dsp)
+{
+ regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0);
+ regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0);
+ regmap_write(dsp->regmap, dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
+}
+
+static void wm_adsp_boot_work(struct work_struct *work)
{
struct wm_adsp *dsp = container_of(work,
struct wm_adsp,
@@ -2598,20 +2917,23 @@
mutex_lock(&dsp->pwr_lock);
- ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
- ADSP2_MEM_ENA, ADSP2_MEM_ENA);
- if (ret != 0)
- goto err_mutex;
+ if (dsp->ops->enable_memory) {
+ ret = dsp->ops->enable_memory(dsp);
+ if (ret != 0)
+ goto err_mutex;
+ }
- ret = wm_adsp2_ena(dsp);
- if (ret != 0)
- goto err_mem;
+ if (dsp->ops->enable_core) {
+ ret = dsp->ops->enable_core(dsp);
+ if (ret != 0)
+ goto err_mem;
+ }
ret = wm_adsp_load(dsp);
if (ret != 0)
goto err_ena;
- ret = wm_adsp2_setup_algs(dsp);
+ ret = dsp->ops->setup_algs(dsp);
if (ret != 0)
goto err_ena;
@@ -2624,17 +2946,8 @@
if (ret != 0)
goto err_ena;
- switch (dsp->rev) {
- case 0:
- /* Turn DSP back off until we are ready to run */
- ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
- ADSP2_SYS_ENA, 0);
- if (ret != 0)
- goto err_ena;
- break;
- default:
- break;
- }
+ if (dsp->ops->disable_core)
+ dsp->ops->disable_core(dsp);
dsp->booted = true;
@@ -2643,35 +2956,62 @@
return;
err_ena:
- regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
- ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+ if (dsp->ops->disable_core)
+ dsp->ops->disable_core(dsp);
err_mem:
- regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
- ADSP2_MEM_ENA, 0);
+ if (dsp->ops->disable_memory)
+ dsp->ops->disable_memory(dsp);
err_mutex:
mutex_unlock(&dsp->pwr_lock);
}
-static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
+static int wm_halo_configure_mpu(struct wm_adsp *dsp, unsigned int lock_regions)
{
+ struct reg_sequence config[] = {
+ { dsp->base + HALO_MPU_LOCK_CONFIG, 0x5555 },
+ { dsp->base + HALO_MPU_LOCK_CONFIG, 0xAAAA },
+ { dsp->base + HALO_MPU_XMEM_ACCESS_0, 0xFFFFFFFF },
+ { dsp->base + HALO_MPU_YMEM_ACCESS_0, 0xFFFFFFFF },
+ { dsp->base + HALO_MPU_WINDOW_ACCESS_0, lock_regions },
+ { dsp->base + HALO_MPU_XREG_ACCESS_0, lock_regions },
+ { dsp->base + HALO_MPU_YREG_ACCESS_0, lock_regions },
+ { dsp->base + HALO_MPU_XMEM_ACCESS_1, 0xFFFFFFFF },
+ { dsp->base + HALO_MPU_YMEM_ACCESS_1, 0xFFFFFFFF },
+ { dsp->base + HALO_MPU_WINDOW_ACCESS_1, lock_regions },
+ { dsp->base + HALO_MPU_XREG_ACCESS_1, lock_regions },
+ { dsp->base + HALO_MPU_YREG_ACCESS_1, lock_regions },
+ { dsp->base + HALO_MPU_XMEM_ACCESS_2, 0xFFFFFFFF },
+ { dsp->base + HALO_MPU_YMEM_ACCESS_2, 0xFFFFFFFF },
+ { dsp->base + HALO_MPU_WINDOW_ACCESS_2, lock_regions },
+ { dsp->base + HALO_MPU_XREG_ACCESS_2, lock_regions },
+ { dsp->base + HALO_MPU_YREG_ACCESS_2, lock_regions },
+ { dsp->base + HALO_MPU_XMEM_ACCESS_3, 0xFFFFFFFF },
+ { dsp->base + HALO_MPU_YMEM_ACCESS_3, 0xFFFFFFFF },
+ { dsp->base + HALO_MPU_WINDOW_ACCESS_3, lock_regions },
+ { dsp->base + HALO_MPU_XREG_ACCESS_3, lock_regions },
+ { dsp->base + HALO_MPU_YREG_ACCESS_3, lock_regions },
+ { dsp->base + HALO_MPU_LOCK_CONFIG, 0 },
+ };
+
+ return regmap_multi_reg_write(dsp->regmap, config, ARRAY_SIZE(config));
+}
+
+int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
+ struct wm_adsp *dsp = &dsps[w->shift];
int ret;
- switch (dsp->rev) {
- case 0:
- ret = regmap_update_bits_async(dsp->regmap,
- dsp->base + ADSP2_CLOCKING,
- ADSP2_CLK_SEL_MASK,
- freq << ADSP2_CLK_SEL_SHIFT);
- if (ret) {
- adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
- return;
- }
- break;
- default:
- /* clock is handled by parent codec driver */
- break;
- }
+ ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CLOCKING,
+ ADSP2_CLK_SEL_MASK,
+ freq << ADSP2_CLK_SEL_SHIFT);
+ if (ret)
+ adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
+
+ return ret;
}
+EXPORT_SYMBOL_GPL(wm_adsp2_set_dspclk);
int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -2718,19 +3058,18 @@
static void wm_adsp_stop_watchdog(struct wm_adsp *dsp)
{
- switch (dsp->rev) {
- case 0:
- case 1:
- return;
- default:
- regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
- ADSP2_WDT_ENA_MASK, 0);
- }
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG,
+ ADSP2_WDT_ENA_MASK, 0);
}
-int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event,
- unsigned int freq)
+static void wm_halo_stop_watchdog(struct wm_adsp *dsp)
+{
+ regmap_update_bits(dsp->regmap, dsp->base + HALO_WDT_CONTROL,
+ HALO_WDT_EN_MASK, 0);
+}
+
+int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
@@ -2739,7 +3078,6 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- wm_adsp2_set_dspclk(dsp, freq);
queue_work(system_unbound_wq, &dsp->boot_work);
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -2752,8 +3090,8 @@
dsp->booted = false;
- regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
- ADSP2_MEM_ENA, 0);
+ if (dsp->ops->disable_memory)
+ dsp->ops->disable_memory(dsp);
list_for_each_entry(ctl, &dsp->ctl_list, list)
ctl->enabled = 0;
@@ -2770,10 +3108,23 @@
return 0;
}
-EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
+EXPORT_SYMBOL_GPL(wm_adsp_early_event);
-int wm_adsp2_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int wm_adsp2_start_core(struct wm_adsp *dsp)
+{
+ return regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_CORE_ENA | ADSP2_START,
+ ADSP2_CORE_ENA | ADSP2_START);
+}
+
+static void wm_adsp2_stop_core(struct wm_adsp *dsp)
+{
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_CORE_ENA | ADSP2_START, 0);
+}
+
+int wm_adsp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
@@ -2791,23 +3142,31 @@
goto err;
}
- ret = wm_adsp2_ena(dsp);
- if (ret != 0)
- goto err;
+ if (dsp->ops->enable_core) {
+ ret = dsp->ops->enable_core(dsp);
+ if (ret != 0)
+ goto err;
+ }
/* Sync set controls */
ret = wm_coeff_sync_controls(dsp);
if (ret != 0)
goto err;
- wm_adsp2_lock(dsp, dsp->lock_regions);
+ if (dsp->ops->lock_memory) {
+ ret = dsp->ops->lock_memory(dsp, dsp->lock_regions);
+ if (ret != 0) {
+ adsp_err(dsp, "Error configuring MPU: %d\n",
+ ret);
+ goto err;
+ }
+ }
- ret = regmap_update_bits(dsp->regmap,
- dsp->base + ADSP2_CONTROL,
- ADSP2_CORE_ENA | ADSP2_START,
- ADSP2_CORE_ENA | ADSP2_START);
- if (ret != 0)
- goto err;
+ if (dsp->ops->start_core) {
+ ret = dsp->ops->start_core(dsp);
+ if (ret != 0)
+ goto err;
+ }
if (wm_adsp_fw[dsp->fw].num_caps != 0) {
ret = wm_adsp_buffer_init(dsp);
@@ -2818,60 +3177,33 @@
dsp->running = true;
mutex_unlock(&dsp->pwr_lock);
-
break;
case SND_SOC_DAPM_PRE_PMD:
/* Tell the firmware to cleanup */
wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN);
- wm_adsp_stop_watchdog(dsp);
+ if (dsp->ops->stop_watchdog)
+ dsp->ops->stop_watchdog(dsp);
/* Log firmware state, it can be useful for analysis */
- switch (dsp->rev) {
- case 0:
- wm_adsp2_show_fw_status(dsp);
- break;
- default:
- wm_adsp2v2_show_fw_status(dsp);
- break;
- }
+ if (dsp->ops->show_fw_status)
+ dsp->ops->show_fw_status(dsp);
mutex_lock(&dsp->pwr_lock);
dsp->running = false;
- regmap_update_bits(dsp->regmap,
- dsp->base + ADSP2_CONTROL,
- ADSP2_CORE_ENA | ADSP2_START, 0);
-
- /* Make sure DMAs are quiesced */
- switch (dsp->rev) {
- case 0:
- regmap_write(dsp->regmap,
- dsp->base + ADSP2_RDMA_CONFIG_1, 0);
- regmap_write(dsp->regmap,
- dsp->base + ADSP2_WDMA_CONFIG_1, 0);
- regmap_write(dsp->regmap,
- dsp->base + ADSP2_WDMA_CONFIG_2, 0);
-
- regmap_update_bits(dsp->regmap,
- dsp->base + ADSP2_CONTROL,
- ADSP2_SYS_ENA, 0);
- break;
- default:
- regmap_write(dsp->regmap,
- dsp->base + ADSP2_RDMA_CONFIG_1, 0);
- regmap_write(dsp->regmap,
- dsp->base + ADSP2_WDMA_CONFIG_1, 0);
- regmap_write(dsp->regmap,
- dsp->base + ADSP2V2_WDMA_CONFIG_2, 0);
- break;
- }
+ if (dsp->ops->stop_core)
+ dsp->ops->stop_core(dsp);
+ if (dsp->ops->disable_core)
+ dsp->ops->disable_core(dsp);
if (wm_adsp_fw[dsp->fw].num_caps != 0)
wm_adsp_buffer_free(dsp);
+ dsp->fatal_error = false;
+
mutex_unlock(&dsp->pwr_lock);
adsp_dbg(dsp, "Execution stopped\n");
@@ -2883,12 +3215,31 @@
return 0;
err:
- regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
- ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+ if (dsp->ops->stop_core)
+ dsp->ops->stop_core(dsp);
+ if (dsp->ops->disable_core)
+ dsp->ops->disable_core(dsp);
mutex_unlock(&dsp->pwr_lock);
return ret;
}
-EXPORT_SYMBOL_GPL(wm_adsp2_event);
+EXPORT_SYMBOL_GPL(wm_adsp_event);
+
+static int wm_halo_start_core(struct wm_adsp *dsp)
+{
+ return regmap_update_bits(dsp->regmap,
+ dsp->base + HALO_CCM_CORE_CONTROL,
+ HALO_CORE_EN, HALO_CORE_EN);
+}
+
+static void wm_halo_stop_core(struct wm_adsp *dsp)
+{
+ regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL,
+ HALO_CORE_EN, 0);
+
+ /* reset halo core with CORE_SOFT_RESET */
+ regmap_update_bits(dsp->regmap, dsp->base + HALO_CORE_SOFT_RESET,
+ HALO_CORE_SOFT_RESET_MASK, 1);
+}
int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component)
{
@@ -2917,7 +3268,7 @@
{
int ret;
- ret = wm_adsp_create_name(dsp);
+ ret = wm_adsp_common_init(dsp);
if (ret)
return ret;
@@ -2934,21 +3285,39 @@
"Failed to clear memory retention: %d\n", ret);
return ret;
}
+
+ dsp->ops = &wm_adsp2_ops[0];
+ break;
+ case 1:
+ dsp->ops = &wm_adsp2_ops[1];
break;
default:
+ dsp->ops = &wm_adsp2_ops[2];
break;
}
- INIT_LIST_HEAD(&dsp->alg_regions);
- INIT_LIST_HEAD(&dsp->ctl_list);
- INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work);
-
- mutex_init(&dsp->pwr_lock);
+ INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_init);
+int wm_halo_init(struct wm_adsp *dsp)
+{
+ int ret;
+
+ ret = wm_adsp_common_init(dsp);
+ if (ret)
+ return ret;
+
+ dsp->ops = &wm_halo_ops;
+
+ INIT_WORK(&dsp->boot_work, wm_adsp_boot_work);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm_halo_init);
+
void wm_adsp2_remove(struct wm_adsp *dsp)
{
struct wm_coeff_ctl *ctl;
@@ -2969,15 +3338,23 @@
static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)
{
- /*
- * Note this will be more complex once each DSP can support multiple
- * streams
- */
- if (!compr->dsp->buffer)
+ struct wm_adsp_compr_buf *buf = NULL, *tmp;
+
+ if (compr->dsp->fatal_error)
return -EINVAL;
- compr->buf = compr->dsp->buffer;
- compr->buf->compr = compr;
+ list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {
+ if (!tmp->name || !strcmp(compr->name, tmp->name)) {
+ buf = tmp;
+ break;
+ }
+ }
+
+ if (!buf)
+ return -EINVAL;
+
+ compr->buf = buf;
+ buf->compr = compr;
return 0;
}
@@ -2999,28 +3376,33 @@
int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
{
- struct wm_adsp_compr *compr;
+ struct wm_adsp_compr *compr, *tmp;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
int ret = 0;
mutex_lock(&dsp->pwr_lock);
if (wm_adsp_fw[dsp->fw].num_caps == 0) {
- adsp_err(dsp, "Firmware does not support compressed API\n");
+ adsp_err(dsp, "%s: Firmware does not support compressed API\n",
+ rtd->codec_dai->name);
ret = -ENXIO;
goto out;
}
if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
- adsp_err(dsp, "Firmware does not support stream direction\n");
+ adsp_err(dsp, "%s: Firmware does not support stream direction\n",
+ rtd->codec_dai->name);
ret = -EINVAL;
goto out;
}
- if (dsp->compr) {
- /* It is expect this limitation will be removed in future */
- adsp_err(dsp, "Only a single stream supported per DSP\n");
- ret = -EBUSY;
- goto out;
+ list_for_each_entry(tmp, &dsp->compr_list, list) {
+ if (!strcmp(tmp->name, rtd->codec_dai->name)) {
+ adsp_err(dsp, "%s: Only a single stream supported per dai\n",
+ rtd->codec_dai->name);
+ ret = -EBUSY;
+ goto out;
+ }
}
compr = kzalloc(sizeof(*compr), GFP_KERNEL);
@@ -3031,8 +3413,9 @@
compr->dsp = dsp;
compr->stream = stream;
+ compr->name = rtd->codec_dai->name;
- dsp->compr = compr;
+ list_add_tail(&compr->list, &dsp->compr_list);
stream->runtime->private_data = compr;
@@ -3051,7 +3434,7 @@
mutex_lock(&dsp->pwr_lock);
wm_adsp_compr_detach(compr);
- dsp->compr = NULL;
+ list_del(&compr->list);
kfree(compr->raw_buf);
kfree(compr);
@@ -3076,9 +3459,9 @@
params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS ||
params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS ||
params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) {
- adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n",
- params->buffer.fragment_size,
- params->buffer.fragments);
+ compr_err(compr, "Invalid buffer fragsize=%d fragments=%d\n",
+ params->buffer.fragment_size,
+ params->buffer.fragments);
return -EINVAL;
}
@@ -3106,9 +3489,9 @@
return 0;
}
- adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
- params->codec.id, params->codec.ch_in, params->codec.ch_out,
- params->codec.sample_rate, params->codec.format);
+ compr_err(compr, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n",
+ params->codec.id, params->codec.ch_in, params->codec.ch_out,
+ params->codec.sample_rate, params->codec.format);
return -EINVAL;
}
@@ -3130,8 +3513,8 @@
compr->size = params->buffer;
- adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n",
- compr->size.fragment_size, compr->size.fragments);
+ compr_dbg(compr, "fragment_size=%d fragments=%d\n",
+ compr->size.fragment_size, compr->size.fragments);
size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf);
compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL);
@@ -3179,7 +3562,7 @@
if (!mem)
return -EINVAL;
- reg = wm_adsp_region_to_reg(mem, mem_addr);
+ reg = dsp->ops->region_to_reg(mem, mem_addr);
ret = regmap_raw_read(dsp->regmap, reg, data,
sizeof(*data) * num_words);
@@ -3207,7 +3590,7 @@
if (!mem)
return -EINVAL;
- reg = wm_adsp_region_to_reg(mem, mem_addr);
+ reg = dsp->ops->region_to_reg(mem, mem_addr);
data = cpu_to_be32(data & 0x00ffffffu);
@@ -3217,109 +3600,30 @@
static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf,
unsigned int field_offset, u32 *data)
{
- return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM,
+ return wm_adsp_read_data_word(buf->dsp, buf->host_buf_mem_type,
buf->host_buf_ptr + field_offset, data);
}
static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
unsigned int field_offset, u32 data)
{
- return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM,
+ return wm_adsp_write_data_word(buf->dsp, buf->host_buf_mem_type,
buf->host_buf_ptr + field_offset, data);
}
-static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
+static void wm_adsp_remove_padding(u32 *buf, int nwords, int data_word_size)
{
- struct wm_adsp_alg_region *alg_region;
- struct wm_adsp *dsp = buf->dsp;
- u32 xmalg, addr, magic;
- int i, ret;
+ u8 *pack_in = (u8 *)buf;
+ u8 *pack_out = (u8 *)buf;
+ int i, j;
- alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
- xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32);
+ /* Remove the padding bytes from the data read from the DSP */
+ for (i = 0; i < nwords; i++) {
+ for (j = 0; j < data_word_size; j++)
+ *pack_out++ = *pack_in++;
- addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
- ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
- if (ret < 0)
- return ret;
-
- if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
- return -EINVAL;
-
- addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
- for (i = 0; i < 5; ++i) {
- ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
- &buf->host_buf_ptr);
- if (ret < 0)
- return ret;
-
- if (buf->host_buf_ptr)
- break;
-
- usleep_range(1000, 2000);
+ pack_in += sizeof(*buf) - data_word_size;
}
-
- if (!buf->host_buf_ptr)
- return -EIO;
-
- adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
-
- 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, ®);
- 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)
@@ -3329,6 +3633,11 @@
u32 offset = 0;
int i, ret;
+ buf->regions = kcalloc(caps->num_regions, sizeof(*buf->regions),
+ GFP_KERNEL);
+ if (!buf->regions)
+ return -ENOMEM;
+
for (i = 0; i < caps->num_regions; ++i) {
region = &buf->regions[i];
@@ -3347,10 +3656,10 @@
region->cumulative_size = offset;
- adsp_dbg(buf->dsp,
- "region=%d type=%d base=%04x off=%04x size=%04x\n",
- i, region->mem_type, region->base_addr,
- region->offset, region->cumulative_size);
+ compr_dbg(buf,
+ "region=%d type=%d base=%08x off=%08x size=%08x\n",
+ i, region->mem_type, region->base_addr,
+ region->offset, region->cumulative_size);
}
return 0;
@@ -3363,58 +3672,222 @@
buf->avail = 0;
}
-static int wm_adsp_buffer_init(struct wm_adsp *dsp)
+static struct wm_adsp_compr_buf *wm_adsp_buffer_alloc(struct wm_adsp *dsp)
{
struct wm_adsp_compr_buf *buf;
- int ret;
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
- return -ENOMEM;
+ return NULL;
buf->dsp = dsp;
wm_adsp_buffer_clear(buf);
- ret = wm_adsp_buffer_locate(buf);
- if (ret < 0) {
- adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret);
- goto err_buffer;
+ list_add_tail(&buf->list, &dsp->buffer_list);
+
+ return buf;
+}
+
+static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
+{
+ struct wm_adsp_alg_region *alg_region;
+ struct wm_adsp_compr_buf *buf;
+ u32 xmalg, addr, magic;
+ int i, ret;
+
+ alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id);
+ if (!alg_region) {
+ adsp_err(dsp, "No algorithm region found\n");
+ return -EINVAL;
}
- buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions,
- sizeof(*buf->regions), GFP_KERNEL);
- if (!buf->regions) {
- ret = -ENOMEM;
- goto err_buffer;
+ buf = wm_adsp_buffer_alloc(dsp);
+ if (!buf)
+ return -ENOMEM;
+
+ xmalg = dsp->ops->sys_config_size / sizeof(__be32);
+
+ addr = alg_region->base + xmalg + ALG_XM_FIELD(magic);
+ ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic);
+ if (ret < 0)
+ return ret;
+
+ if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC)
+ return -ENODEV;
+
+ addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr);
+ for (i = 0; i < 5; ++i) {
+ ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr,
+ &buf->host_buf_ptr);
+ if (ret < 0)
+ return ret;
+
+ if (buf->host_buf_ptr)
+ break;
+
+ usleep_range(1000, 2000);
}
+ if (!buf->host_buf_ptr)
+ return -EIO;
+
+ buf->host_buf_mem_type = WMFW_ADSP2_XM;
+
ret = wm_adsp_buffer_populate(buf);
- if (ret < 0) {
- adsp_err(dsp, "Failed to populate host buffer: %d\n", ret);
- goto err_regions;
+ if (ret < 0)
+ return ret;
+
+ compr_dbg(buf, "legacy host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+ return 0;
+}
+
+static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
+{
+ struct wm_adsp_host_buf_coeff_v1 coeff_v1;
+ struct wm_adsp_compr_buf *buf;
+ unsigned int val, reg;
+ int ret, i;
+
+ ret = wm_coeff_base_reg(ctl, ®);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < 5; ++i) {
+ ret = regmap_raw_read(ctl->dsp->regmap, reg, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ if (val)
+ break;
+
+ usleep_range(1000, 2000);
}
- dsp->buffer = buf;
+ if (!val) {
+ adsp_err(ctl->dsp, "Failed to acquire host buffer\n");
+ return -EIO;
+ }
+
+ buf = wm_adsp_buffer_alloc(ctl->dsp);
+ if (!buf)
+ return -ENOMEM;
+
+ buf->host_buf_mem_type = ctl->alg_region.type;
+ buf->host_buf_ptr = be32_to_cpu(val);
+
+ ret = wm_adsp_buffer_populate(buf);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * v0 host_buffer coefficients didn't have versioning, so if the
+ * control is one word, assume version 0.
+ */
+ if (ctl->len == 4) {
+ compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+ return 0;
+ }
+
+ ret = regmap_raw_read(ctl->dsp->regmap, reg, &coeff_v1,
+ sizeof(coeff_v1));
+ if (ret < 0)
+ return ret;
+
+ coeff_v1.versions = be32_to_cpu(coeff_v1.versions);
+ val = coeff_v1.versions & HOST_BUF_COEFF_COMPAT_VER_MASK;
+ val >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
+
+ if (val > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
+ adsp_err(ctl->dsp,
+ "Host buffer coeff ver %u > supported version %u\n",
+ val, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(coeff_v1.name); i++)
+ coeff_v1.name[i] = be32_to_cpu(coeff_v1.name[i]);
+
+ wm_adsp_remove_padding((u32 *)&coeff_v1.name,
+ ARRAY_SIZE(coeff_v1.name),
+ WM_ADSP_DATA_WORD_SIZE);
+
+ buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part,
+ (char *)&coeff_v1.name);
+
+ compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
+ buf->host_buf_ptr, val);
+
+ return val;
+}
+
+static int wm_adsp_buffer_init(struct wm_adsp *dsp)
+{
+ struct wm_coeff_ctl *ctl;
+ int ret;
+
+ list_for_each_entry(ctl, &dsp->ctl_list, list) {
+ if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
+ continue;
+
+ if (!ctl->enabled)
+ continue;
+
+ ret = wm_adsp_buffer_parse_coeff(ctl);
+ if (ret < 0) {
+ adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
+ goto error;
+ } else if (ret == 0) {
+ /* Only one buffer supported for version 0 */
+ return 0;
+ }
+ }
+
+ 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;
+ }
+ }
return 0;
-err_regions:
- kfree(buf->regions);
-err_buffer:
- kfree(buf);
+error:
+ wm_adsp_buffer_free(dsp);
return ret;
}
static int wm_adsp_buffer_free(struct wm_adsp *dsp)
{
- if (dsp->buffer) {
- wm_adsp_compr_detach(dsp->buffer->compr);
+ struct wm_adsp_compr_buf *buf, *tmp;
- kfree(dsp->buffer->regions);
- kfree(dsp->buffer);
+ list_for_each_entry_safe(buf, tmp, &dsp->buffer_list, list) {
+ wm_adsp_compr_detach(buf->compr);
- dsp->buffer = NULL;
+ kfree(buf->name);
+ kfree(buf->regions);
+ list_del(&buf->list);
+ kfree(buf);
+ }
+
+ return 0;
+}
+
+static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
+{
+ int ret;
+
+ ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
+ if (ret < 0) {
+ compr_err(buf, "Failed to check buffer error: %d\n", ret);
+ return ret;
+ }
+ if (buf->error != 0) {
+ compr_err(buf, "Buffer error occurred: %d\n", buf->error);
+ return -EIO;
}
return 0;
@@ -3426,7 +3899,7 @@
struct wm_adsp *dsp = compr->dsp;
int ret = 0;
- adsp_dbg(dsp, "Trigger: %d\n", cmd);
+ compr_dbg(compr, "Trigger: %d\n", cmd);
mutex_lock(&dsp->pwr_lock);
@@ -3435,25 +3908,29 @@
if (!wm_adsp_compr_attached(compr)) {
ret = wm_adsp_compr_attach(compr);
if (ret < 0) {
- adsp_err(dsp, "Failed to link buffer and stream: %d\n",
- ret);
+ compr_err(compr, "Failed to link buffer and stream: %d\n",
+ ret);
break;
}
}
- wm_adsp_buffer_clear(compr->buf);
+ ret = wm_adsp_buffer_get_error(compr->buf);
+ if (ret < 0)
+ break;
/* Trigger the IRQ at one fragment of data */
ret = wm_adsp_buffer_write(compr->buf,
HOST_BUFFER_FIELD(high_water_mark),
wm_adsp_compr_frag_words(compr));
if (ret < 0) {
- adsp_err(dsp, "Failed to set high water mark: %d\n",
- ret);
+ compr_err(compr, "Failed to set high water mark: %d\n",
+ ret);
break;
}
break;
case SNDRV_PCM_TRIGGER_STOP:
+ if (wm_adsp_compr_attached(compr))
+ wm_adsp_buffer_clear(compr->buf);
break;
default:
ret = -EINVAL;
@@ -3490,7 +3967,7 @@
read_index = sign_extend32(next_read_index, 23);
if (read_index < 0) {
- adsp_dbg(buf->dsp, "Avail check on unstarted stream\n");
+ compr_dbg(buf, "Avail check on unstarted stream\n");
return 0;
}
@@ -3508,31 +3985,14 @@
if (avail < 0)
avail += wm_adsp_buffer_size(buf);
- adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
- buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
+ compr_dbg(buf, "readindex=0x%x, writeindex=0x%x, avail=%d\n",
+ buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE);
buf->avail = avail;
return 0;
}
-static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)
-{
- int ret;
-
- ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);
- if (ret < 0) {
- adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret);
- return ret;
- }
- if (buf->error != 0) {
- adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error);
- return -EIO;
- }
-
- return 0;
-}
-
int wm_adsp_compr_handle_irq(struct wm_adsp *dsp)
{
struct wm_adsp_compr_buf *buf;
@@ -3541,39 +4001,40 @@
mutex_lock(&dsp->pwr_lock);
- buf = dsp->buffer;
- compr = dsp->compr;
-
- if (!buf) {
+ if (list_empty(&dsp->buffer_list)) {
ret = -ENODEV;
goto out;
}
adsp_dbg(dsp, "Handling buffer IRQ\n");
- ret = wm_adsp_buffer_get_error(buf);
- if (ret < 0)
- goto out_notify; /* Wake poll to report error */
+ list_for_each_entry(buf, &dsp->buffer_list, list) {
+ compr = buf->compr;
- ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
- &buf->irq_count);
- if (ret < 0) {
- adsp_err(dsp, "Failed to get irq_count: %d\n", ret);
- goto out;
- }
+ ret = wm_adsp_buffer_get_error(buf);
+ if (ret < 0)
+ goto out_notify; /* Wake poll to report error */
- ret = wm_adsp_buffer_update_avail(buf);
- if (ret < 0) {
- adsp_err(dsp, "Error reading avail: %d\n", ret);
- goto out;
- }
+ ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count),
+ &buf->irq_count);
+ if (ret < 0) {
+ compr_err(buf, "Failed to get irq_count: %d\n", ret);
+ goto out;
+ }
- if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
- ret = WM_ADSP_COMPR_VOICE_TRIGGER;
+ ret = wm_adsp_buffer_update_avail(buf);
+ if (ret < 0) {
+ compr_err(buf, "Error reading avail: %d\n", ret);
+ goto out;
+ }
+
+ if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2)
+ ret = WM_ADSP_COMPR_VOICE_TRIGGER;
out_notify:
- if (compr && compr->stream)
- snd_compr_fragment_elapsed(compr->stream);
+ if (compr && compr->stream)
+ snd_compr_fragment_elapsed(compr->stream);
+ }
out:
mutex_unlock(&dsp->pwr_lock);
@@ -3587,8 +4048,7 @@
if (buf->irq_count & 0x01)
return 0;
- adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n",
- buf->irq_count);
+ compr_dbg(buf, "Enable IRQ(0x%x) for next fragment\n", buf->irq_count);
buf->irq_count |= 0x01;
@@ -3604,13 +4064,13 @@
struct wm_adsp_compr_buf *buf;
int ret = 0;
- adsp_dbg(dsp, "Pointer request\n");
+ compr_dbg(compr, "Pointer request\n");
mutex_lock(&dsp->pwr_lock);
buf = compr->buf;
- if (!compr->buf || compr->buf->error) {
+ if (dsp->fatal_error || !buf || buf->error) {
snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
ret = -EIO;
goto out;
@@ -3619,7 +4079,7 @@
if (buf->avail < wm_adsp_compr_frag_words(compr)) {
ret = wm_adsp_buffer_update_avail(buf);
if (ret < 0) {
- adsp_err(dsp, "Error reading avail: %d\n", ret);
+ compr_err(compr, "Error reading avail: %d\n", ret);
goto out;
}
@@ -3630,7 +4090,7 @@
if (buf->avail < wm_adsp_compr_frag_words(compr)) {
ret = wm_adsp_buffer_get_error(buf);
if (ret < 0) {
- if (compr->buf->error)
+ if (buf->error)
snd_compr_stop_error(stream,
SNDRV_PCM_STATE_XRUN);
goto out;
@@ -3638,9 +4098,8 @@
ret = wm_adsp_buffer_reenable_irq(buf);
if (ret < 0) {
- adsp_err(dsp,
- "Failed to re-enable buffer IRQ: %d\n",
- ret);
+ compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
+ ret);
goto out;
}
}
@@ -3660,11 +4119,9 @@
static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target)
{
struct wm_adsp_compr_buf *buf = compr->buf;
- u8 *pack_in = (u8 *)compr->raw_buf;
- u8 *pack_out = (u8 *)compr->raw_buf;
unsigned int adsp_addr;
int mem_type, nwords, max_read;
- int i, j, ret;
+ int i, ret;
/* Calculate read parameters */
for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i)
@@ -3696,13 +4153,7 @@
if (ret < 0)
return ret;
- /* Remove the padding bytes from the data read from the DSP */
- for (i = 0; i < nwords; i++) {
- for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++)
- *pack_out++ = *pack_in++;
-
- pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE;
- }
+ wm_adsp_remove_padding(compr->raw_buf, nwords, WM_ADSP_DATA_WORD_SIZE);
/* update read index to account for words read */
buf->read_index += nwords;
@@ -3727,9 +4178,9 @@
int ntotal = 0;
int nwords, nbytes;
- adsp_dbg(dsp, "Requested read of %zu bytes\n", count);
+ compr_dbg(compr, "Requested read of %zu bytes\n", count);
- if (!compr->buf || compr->buf->error) {
+ if (dsp->fatal_error || !compr->buf || compr->buf->error) {
snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN);
return -EIO;
}
@@ -3739,17 +4190,18 @@
do {
nwords = wm_adsp_buffer_capture_block(compr, count);
if (nwords < 0) {
- adsp_err(dsp, "Failed to capture block: %d\n", nwords);
+ compr_err(compr, "Failed to capture block: %d\n",
+ nwords);
return nwords;
}
nbytes = nwords * WM_ADSP_DATA_WORD_SIZE;
- adsp_dbg(dsp, "Read %d bytes\n", nbytes);
+ compr_dbg(compr, "Read %d bytes\n", nbytes);
if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) {
- adsp_err(dsp, "Failed to copy data to user: %d, %d\n",
- ntotal, nbytes);
+ compr_err(compr, "Failed to copy data to user: %d, %d\n",
+ ntotal, nbytes);
return -EFAULT;
}
@@ -3782,53 +4234,38 @@
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
-int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)
+static void wm_adsp_fatal_error(struct wm_adsp *dsp)
{
- struct regmap *regmap = dsp->regmap;
- unsigned int code0, code1, lock_reg;
+ struct wm_adsp_compr *compr;
- if (!(lock_regions & WM_ADSP2_REGION_ALL))
- return 0;
+ dsp->fatal_error = true;
- lock_regions &= WM_ADSP2_REGION_ALL;
- lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0;
-
- while (lock_regions) {
- code0 = code1 = 0;
- if (lock_regions & BIT(0)) {
- code0 = ADSP2_LOCK_CODE_0;
- code1 = ADSP2_LOCK_CODE_1;
- }
- if (lock_regions & BIT(1)) {
- code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT;
- code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT;
- }
- regmap_write(regmap, lock_reg, code0);
- regmap_write(regmap, lock_reg, code1);
- lock_regions >>= 2;
- lock_reg += 2;
+ list_for_each_entry(compr, &dsp->compr_list, list) {
+ if (compr->stream)
+ snd_compr_fragment_elapsed(compr->stream);
}
-
- return 0;
}
-EXPORT_SYMBOL_GPL(wm_adsp2_lock);
-irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)
+irqreturn_t wm_adsp2_bus_error(int irq, void *data)
{
+ struct wm_adsp *dsp = (struct wm_adsp *)data;
unsigned int val;
struct regmap *regmap = dsp->regmap;
int ret = 0;
+ mutex_lock(&dsp->pwr_lock);
+
ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);
if (ret) {
adsp_err(dsp,
"Failed to read Region Lock Ctrl register: %d\n", ret);
- return IRQ_HANDLED;
+ goto error;
}
if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {
adsp_err(dsp, "watchdog timeout error\n");
- wm_adsp_stop_watchdog(dsp);
+ dsp->ops->stop_watchdog(dsp);
+ wm_adsp_fatal_error(dsp);
}
if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) {
@@ -3842,7 +4279,7 @@
adsp_err(dsp,
"Failed to read Bus Err Addr register: %d\n",
ret);
- return IRQ_HANDLED;
+ goto error;
}
adsp_err(dsp, "bus error address = 0x%x\n",
@@ -3855,7 +4292,7 @@
adsp_err(dsp,
"Failed to read Pmem Xmem Err Addr register: %d\n",
ret);
- return IRQ_HANDLED;
+ goto error;
}
adsp_err(dsp, "xmem error address = 0x%x\n",
@@ -3868,8 +4305,167 @@
regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,
ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT);
+error:
+ mutex_unlock(&dsp->pwr_lock);
+
return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(wm_adsp2_bus_error);
+irqreturn_t wm_halo_bus_error(int irq, void *data)
+{
+ struct wm_adsp *dsp = (struct wm_adsp *)data;
+ struct regmap *regmap = dsp->regmap;
+ unsigned int fault[6];
+ struct reg_sequence clear[] = {
+ { dsp->base + HALO_MPU_XM_VIO_STATUS, 0x0 },
+ { dsp->base + HALO_MPU_YM_VIO_STATUS, 0x0 },
+ { dsp->base + HALO_MPU_PM_VIO_STATUS, 0x0 },
+ };
+ int ret;
+
+ mutex_lock(&dsp->pwr_lock);
+
+ ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1,
+ fault);
+ if (ret) {
+ adsp_warn(dsp, "Failed to read AHB DEBUG_1: %d\n", ret);
+ goto exit_unlock;
+ }
+
+ adsp_warn(dsp, "AHB: STATUS: 0x%x ADDR: 0x%x\n",
+ *fault & HALO_AHBM_FLAGS_ERR_MASK,
+ (*fault & HALO_AHBM_CORE_ERR_ADDR_MASK) >>
+ HALO_AHBM_CORE_ERR_ADDR_SHIFT);
+
+ ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0,
+ fault);
+ if (ret) {
+ adsp_warn(dsp, "Failed to read AHB DEBUG_0: %d\n", ret);
+ goto exit_unlock;
+ }
+
+ adsp_warn(dsp, "AHB: SYS_ADDR: 0x%x\n", *fault);
+
+ ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR,
+ fault, ARRAY_SIZE(fault));
+ if (ret) {
+ adsp_warn(dsp, "Failed to read MPU fault info: %d\n", ret);
+ goto exit_unlock;
+ }
+
+ adsp_warn(dsp, "XM: STATUS:0x%x ADDR:0x%x\n", fault[1], fault[0]);
+ adsp_warn(dsp, "YM: STATUS:0x%x ADDR:0x%x\n", fault[3], fault[2]);
+ adsp_warn(dsp, "PM: STATUS:0x%x ADDR:0x%x\n", fault[5], fault[4]);
+
+ ret = regmap_multi_reg_write(dsp->regmap, clear, ARRAY_SIZE(clear));
+ if (ret)
+ adsp_warn(dsp, "Failed to clear MPU status: %d\n", ret);
+
+exit_unlock:
+ mutex_unlock(&dsp->pwr_lock);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(wm_halo_bus_error);
+
+irqreturn_t wm_halo_wdt_expire(int irq, void *data)
+{
+ struct wm_adsp *dsp = data;
+
+ mutex_lock(&dsp->pwr_lock);
+
+ adsp_warn(dsp, "WDT Expiry Fault\n");
+ dsp->ops->stop_watchdog(dsp);
+ wm_adsp_fatal_error(dsp);
+
+ mutex_unlock(&dsp->pwr_lock);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(wm_halo_wdt_expire);
+
+static struct wm_adsp_ops wm_adsp1_ops = {
+ .validate_version = wm_adsp_validate_version,
+ .parse_sizes = wm_adsp1_parse_sizes,
+ .region_to_reg = wm_adsp_region_to_reg,
+};
+
+static struct wm_adsp_ops wm_adsp2_ops[] = {
+ {
+ .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
+ .parse_sizes = wm_adsp2_parse_sizes,
+ .validate_version = wm_adsp_validate_version,
+ .setup_algs = wm_adsp2_setup_algs,
+ .region_to_reg = wm_adsp_region_to_reg,
+
+ .show_fw_status = wm_adsp2_show_fw_status,
+
+ .enable_memory = wm_adsp2_enable_memory,
+ .disable_memory = wm_adsp2_disable_memory,
+
+ .enable_core = wm_adsp2_enable_core,
+ .disable_core = wm_adsp2_disable_core,
+
+ .start_core = wm_adsp2_start_core,
+ .stop_core = wm_adsp2_stop_core,
+
+ },
+ {
+ .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
+ .parse_sizes = wm_adsp2_parse_sizes,
+ .validate_version = wm_adsp_validate_version,
+ .setup_algs = wm_adsp2_setup_algs,
+ .region_to_reg = wm_adsp_region_to_reg,
+
+ .show_fw_status = wm_adsp2v2_show_fw_status,
+
+ .enable_memory = wm_adsp2_enable_memory,
+ .disable_memory = wm_adsp2_disable_memory,
+ .lock_memory = wm_adsp2_lock,
+
+ .enable_core = wm_adsp2v2_enable_core,
+ .disable_core = wm_adsp2v2_disable_core,
+
+ .start_core = wm_adsp2_start_core,
+ .stop_core = wm_adsp2_stop_core,
+ },
+ {
+ .sys_config_size = sizeof(struct wm_adsp_system_config_xm_hdr),
+ .parse_sizes = wm_adsp2_parse_sizes,
+ .validate_version = wm_adsp_validate_version,
+ .setup_algs = wm_adsp2_setup_algs,
+ .region_to_reg = wm_adsp_region_to_reg,
+
+ .show_fw_status = wm_adsp2v2_show_fw_status,
+ .stop_watchdog = wm_adsp_stop_watchdog,
+
+ .enable_memory = wm_adsp2_enable_memory,
+ .disable_memory = wm_adsp2_disable_memory,
+ .lock_memory = wm_adsp2_lock,
+
+ .enable_core = wm_adsp2v2_enable_core,
+ .disable_core = wm_adsp2v2_disable_core,
+
+ .start_core = wm_adsp2_start_core,
+ .stop_core = wm_adsp2_stop_core,
+ },
+};
+
+static struct wm_adsp_ops wm_halo_ops = {
+ .sys_config_size = sizeof(struct wm_halo_system_config_xm_hdr),
+ .parse_sizes = wm_adsp2_parse_sizes,
+ .validate_version = wm_halo_validate_version,
+ .setup_algs = wm_halo_setup_algs,
+ .region_to_reg = wm_halo_region_to_reg,
+
+ .show_fw_status = wm_halo_show_fw_status,
+ .stop_watchdog = wm_halo_stop_watchdog,
+
+ .lock_memory = wm_halo_configure_mpu,
+
+ .start_core = wm_halo_start_core,
+ .stop_core = wm_halo_stop_core,
+};
+
MODULE_LICENSE("GPL v2");