Commit 0700bc2f authored by Simon Trimmer's avatar Simon Trimmer Committed by Mark Brown

ASoC: wm_adsp: Separate generic cs_dsp_coeff_ctl handling

This is preparation for moving the generic DSP support out of ASoC. The
majority of the handling of firmware controls is generic and this change
separates the generic and ASoC specific details into separate structures
and functions and renames the generic code named wm_* to cs_*.
Signed-off-by: default avatarSimon Trimmer <simont@opensource.cirrus.com>
Signed-off-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20210913160057.103842-11-simont@opensource.cirrus.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 6092be2d
...@@ -607,21 +607,8 @@ static const struct { ...@@ -607,21 +607,8 @@ static const struct {
struct wm_coeff_ctl { struct wm_coeff_ctl {
const char *name; const char *name;
const char *fw_name; struct cs_dsp_coeff_ctl *cs_ctl;
/* Subname is needed to match with firmware */
const char *subname;
unsigned int subname_len;
struct cs_dsp_alg_region alg_region;
struct wm_adsp *dsp;
unsigned int enabled:1;
struct list_head list;
void *cache;
unsigned int offset;
size_t len;
unsigned int set:1;
struct soc_bytes_ext bytes_ext; struct soc_bytes_ext bytes_ext;
unsigned int flags;
unsigned int type;
struct work_struct work; struct work_struct work;
}; };
...@@ -938,7 +925,7 @@ static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) ...@@ -938,7 +925,7 @@ static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext)
return container_of(ext, struct wm_coeff_ctl, bytes_ext); return container_of(ext, struct wm_coeff_ctl, bytes_ext);
} }
static int cs_dsp_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg) static int cs_dsp_coeff_base_reg(struct cs_dsp_coeff_ctl *ctl, unsigned int *reg)
{ {
const struct cs_dsp_alg_region *alg_region = &ctl->alg_region; const struct cs_dsp_alg_region *alg_region = &ctl->alg_region;
struct wm_adsp *dsp = ctl->dsp; struct wm_adsp *dsp = ctl->dsp;
...@@ -962,8 +949,9 @@ static int wm_coeff_info(struct snd_kcontrol *kctl, ...@@ -962,8 +949,9 @@ static int wm_coeff_info(struct snd_kcontrol *kctl,
struct soc_bytes_ext *bytes_ext = struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value; (struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
switch (ctl->type) { switch (cs_ctl->type) {
case WMFW_CTL_TYPE_ACKED: case WMFW_CTL_TYPE_ACKED:
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = CS_DSP_ACKED_CTL_MIN_VALUE; uinfo->value.integer.min = CS_DSP_ACKED_CTL_MIN_VALUE;
...@@ -973,14 +961,14 @@ static int wm_coeff_info(struct snd_kcontrol *kctl, ...@@ -973,14 +961,14 @@ static int wm_coeff_info(struct snd_kcontrol *kctl,
break; break;
default: default:
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
uinfo->count = ctl->len; uinfo->count = cs_ctl->len;
break; break;
} }
return 0; return 0;
} }
static int cs_dsp_coeff_write_acked_control(struct wm_coeff_ctl *ctl, static int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl,
unsigned int event_id) unsigned int event_id)
{ {
struct wm_adsp *dsp = ctl->dsp; struct wm_adsp *dsp = ctl->dsp;
...@@ -1040,7 +1028,7 @@ static int cs_dsp_coeff_write_acked_control(struct wm_coeff_ctl *ctl, ...@@ -1040,7 +1028,7 @@ static int cs_dsp_coeff_write_acked_control(struct wm_coeff_ctl *ctl,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static int cs_dsp_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl, static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
const void *buf, size_t len) const void *buf, size_t len)
{ {
struct wm_adsp *dsp = ctl->dsp; struct wm_adsp *dsp = ctl->dsp;
...@@ -1071,7 +1059,7 @@ static int cs_dsp_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl, ...@@ -1071,7 +1059,7 @@ static int cs_dsp_coeff_write_ctrl_raw(struct wm_coeff_ctl *ctl,
return 0; return 0;
} }
static int cs_dsp_coeff_write_ctrl(struct wm_coeff_ctl *ctl, static int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl,
const void *buf, size_t len) const void *buf, size_t len)
{ {
int ret = 0; int ret = 0;
...@@ -1094,12 +1082,13 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, ...@@ -1094,12 +1082,13 @@ static int wm_coeff_put(struct snd_kcontrol *kctl,
struct soc_bytes_ext *bytes_ext = struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value; (struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
char *p = ucontrol->value.bytes.data; char *p = ucontrol->value.bytes.data;
int ret = 0; int ret = 0;
mutex_lock(&ctl->dsp->pwr_lock); mutex_lock(&cs_ctl->dsp->pwr_lock);
ret = cs_dsp_coeff_write_ctrl(ctl, p, ctl->len); ret = cs_dsp_coeff_write_ctrl(cs_ctl, p, cs_ctl->len);
mutex_unlock(&ctl->dsp->pwr_lock); mutex_unlock(&cs_ctl->dsp->pwr_lock);
return ret; return ret;
} }
...@@ -1110,16 +1099,17 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, ...@@ -1110,16 +1099,17 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
struct soc_bytes_ext *bytes_ext = struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value; (struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
int ret = 0; int ret = 0;
mutex_lock(&ctl->dsp->pwr_lock); mutex_lock(&cs_ctl->dsp->pwr_lock);
if (copy_from_user(ctl->cache, bytes, size)) if (copy_from_user(cs_ctl->cache, bytes, size))
ret = -EFAULT; ret = -EFAULT;
else else
ret = cs_dsp_coeff_write_ctrl(ctl, ctl->cache, size); ret = cs_dsp_coeff_write_ctrl(cs_ctl, cs_ctl->cache, size);
mutex_unlock(&ctl->dsp->pwr_lock); mutex_unlock(&cs_ctl->dsp->pwr_lock);
return ret; return ret;
} }
...@@ -1130,25 +1120,26 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl, ...@@ -1130,25 +1120,26 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
struct soc_bytes_ext *bytes_ext = struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value; (struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
unsigned int val = ucontrol->value.integer.value[0]; unsigned int val = ucontrol->value.integer.value[0];
int ret; int ret;
if (val == 0) if (val == 0)
return 0; /* 0 means no event */ return 0; /* 0 means no event */
mutex_lock(&ctl->dsp->pwr_lock); mutex_lock(&cs_ctl->dsp->pwr_lock);
if (ctl->enabled && ctl->dsp->running) if (cs_ctl->enabled && cs_ctl->dsp->running)
ret = cs_dsp_coeff_write_acked_control(ctl, val); ret = cs_dsp_coeff_write_acked_control(cs_ctl, val);
else else
ret = -EPERM; ret = -EPERM;
mutex_unlock(&ctl->dsp->pwr_lock); mutex_unlock(&cs_ctl->dsp->pwr_lock);
return ret; return ret;
} }
static int cs_dsp_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl, static int cs_dsp_coeff_read_ctrl_raw(struct cs_dsp_coeff_ctl *ctl,
void *buf, size_t len) void *buf, size_t len)
{ {
struct wm_adsp *dsp = ctl->dsp; struct wm_adsp *dsp = ctl->dsp;
...@@ -1179,7 +1170,7 @@ static int cs_dsp_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl, ...@@ -1179,7 +1170,7 @@ static int cs_dsp_coeff_read_ctrl_raw(struct wm_coeff_ctl *ctl,
return 0; return 0;
} }
static int cs_dsp_coeff_read_ctrl(struct wm_coeff_ctl *ctl, void *buf, size_t len) static int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, void *buf, size_t len)
{ {
int ret = 0; int ret = 0;
...@@ -1205,12 +1196,13 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, ...@@ -1205,12 +1196,13 @@ static int wm_coeff_get(struct snd_kcontrol *kctl,
struct soc_bytes_ext *bytes_ext = struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value; (struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
char *p = ucontrol->value.bytes.data; char *p = ucontrol->value.bytes.data;
int ret; int ret;
mutex_lock(&ctl->dsp->pwr_lock); mutex_lock(&cs_ctl->dsp->pwr_lock);
ret = cs_dsp_coeff_read_ctrl(ctl, p, ctl->len); ret = cs_dsp_coeff_read_ctrl(cs_ctl, p, cs_ctl->len);
mutex_unlock(&ctl->dsp->pwr_lock); mutex_unlock(&cs_ctl->dsp->pwr_lock);
return ret; return ret;
} }
...@@ -1221,16 +1213,17 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, ...@@ -1221,16 +1213,17 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
struct soc_bytes_ext *bytes_ext = struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *)kctl->private_value; (struct soc_bytes_ext *)kctl->private_value;
struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext);
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
int ret = 0; int ret = 0;
mutex_lock(&ctl->dsp->pwr_lock); mutex_lock(&cs_ctl->dsp->pwr_lock);
ret = cs_dsp_coeff_read_ctrl(ctl, ctl->cache, size); ret = cs_dsp_coeff_read_ctrl(cs_ctl, cs_ctl->cache, size);
if (!ret && copy_to_user(bytes, ctl->cache, size)) if (!ret && copy_to_user(bytes, cs_ctl->cache, size))
ret = -EFAULT; ret = -EFAULT;
mutex_unlock(&ctl->dsp->pwr_lock); mutex_unlock(&cs_ctl->dsp->pwr_lock);
return ret; return ret;
} }
...@@ -1283,12 +1276,10 @@ static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len) ...@@ -1283,12 +1276,10 @@ static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len)
static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
{ {
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
struct snd_kcontrol_new *kcontrol; struct snd_kcontrol_new *kcontrol;
int ret; int ret;
if (!ctl || !ctl->name)
return -EINVAL;
kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
if (!kcontrol) if (!kcontrol)
return -ENOMEM; return -ENOMEM;
...@@ -1298,16 +1289,16 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) ...@@ -1298,16 +1289,16 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
kcontrol->tlv.c = snd_soc_bytes_tlv_callback; kcontrol->tlv.c = snd_soc_bytes_tlv_callback;
kcontrol->private_value = (unsigned long)&ctl->bytes_ext; kcontrol->private_value = (unsigned long)&ctl->bytes_ext;
kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); kcontrol->access = wmfw_convert_flags(cs_ctl->flags, cs_ctl->len);
switch (ctl->type) { switch (cs_ctl->type) {
case WMFW_CTL_TYPE_ACKED: case WMFW_CTL_TYPE_ACKED:
kcontrol->get = wm_coeff_get_acked; kcontrol->get = wm_coeff_get_acked;
kcontrol->put = wm_coeff_put_acked; kcontrol->put = wm_coeff_put_acked;
break; break;
default: default:
if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
ctl->bytes_ext.max = ctl->len; ctl->bytes_ext.max = cs_ctl->len;
ctl->bytes_ext.get = wm_coeff_tlv_get; ctl->bytes_ext.get = wm_coeff_tlv_get;
ctl->bytes_ext.put = wm_coeff_tlv_put; ctl->bytes_ext.put = wm_coeff_tlv_put;
} else { } else {
...@@ -1332,7 +1323,7 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) ...@@ -1332,7 +1323,7 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
static int cs_dsp_coeff_init_control_caches(struct wm_adsp *dsp) static int cs_dsp_coeff_init_control_caches(struct wm_adsp *dsp)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *ctl;
int ret; int ret;
list_for_each_entry(ctl, &dsp->ctl_list, list) { list_for_each_entry(ctl, &dsp->ctl_list, list) {
...@@ -1358,7 +1349,7 @@ static int cs_dsp_coeff_init_control_caches(struct wm_adsp *dsp) ...@@ -1358,7 +1349,7 @@ static int cs_dsp_coeff_init_control_caches(struct wm_adsp *dsp)
static int cs_dsp_coeff_sync_controls(struct wm_adsp *dsp) static int cs_dsp_coeff_sync_controls(struct wm_adsp *dsp)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *ctl;
int ret; int ret;
list_for_each_entry(ctl, &dsp->ctl_list, list) { list_for_each_entry(ctl, &dsp->ctl_list, list) {
...@@ -1378,7 +1369,7 @@ static int cs_dsp_coeff_sync_controls(struct wm_adsp *dsp) ...@@ -1378,7 +1369,7 @@ static int cs_dsp_coeff_sync_controls(struct wm_adsp *dsp)
static void cs_dsp_signal_event_controls(struct wm_adsp *dsp, static void cs_dsp_signal_event_controls(struct wm_adsp *dsp,
unsigned int event) unsigned int event)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *ctl;
int ret; int ret;
list_for_each_entry(ctl, &dsp->ctl_list, list) { list_for_each_entry(ctl, &dsp->ctl_list, list) {
...@@ -1401,47 +1392,30 @@ static void wm_adsp_ctl_work(struct work_struct *work) ...@@ -1401,47 +1392,30 @@ static void wm_adsp_ctl_work(struct work_struct *work)
struct wm_coeff_ctl *ctl = container_of(work, struct wm_coeff_ctl *ctl = container_of(work,
struct wm_coeff_ctl, struct wm_coeff_ctl,
work); work);
wmfw_add_ctl(ctl->cs_ctl->dsp, ctl);
wmfw_add_ctl(ctl->dsp, ctl);
} }
static void cs_dsp_free_ctl_blk(struct wm_coeff_ctl *ctl) static void cs_dsp_free_ctl_blk(struct cs_dsp_coeff_ctl *ctl)
{ {
cancel_work_sync(&ctl->work);
kfree(ctl->cache); kfree(ctl->cache);
kfree(ctl->name);
kfree(ctl->subname); kfree(ctl->subname);
kfree(ctl); kfree(ctl);
} }
static int cs_dsp_create_control(struct wm_adsp *dsp, static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
const struct cs_dsp_alg_region *alg_region,
unsigned int offset, unsigned int len,
const char *subname, unsigned int subname_len,
unsigned int flags, unsigned int type)
{ {
struct wm_adsp *dsp = cs_ctl->dsp;
struct wm_coeff_ctl *ctl; struct wm_coeff_ctl *ctl;
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
const char *region_name; const char *region_name;
int ret; int ret;
list_for_each_entry(ctl, &dsp->ctl_list, list) { if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
ctl->alg_region.alg == alg_region->alg &&
ctl->alg_region.type == alg_region->type) {
if ((!subname && !ctl->subname) ||
(subname && !strncmp(ctl->subname, subname, ctl->subname_len))) {
if (!ctl->enabled)
ctl->enabled = 1;
return 0; return 0;
}
}
}
region_name = cs_dsp_mem_region_name(alg_region->type); region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type);
if (!region_name) { if (!region_name) {
cs_dsp_err(dsp, "Unknown region type: %d\n", alg_region->type); adsp_err(dsp, "Unknown region type: %d\n", cs_ctl->alg_region.type);
return -EINVAL; return -EINVAL;
} }
...@@ -1449,22 +1423,21 @@ static int cs_dsp_create_control(struct wm_adsp *dsp, ...@@ -1449,22 +1423,21 @@ static int cs_dsp_create_control(struct wm_adsp *dsp,
case 0: case 0:
case 1: case 1:
snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x", snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
dsp->name, region_name, alg_region->alg); dsp->name, region_name, cs_ctl->alg_region.alg);
subname = NULL; /* don't append subname */
break; break;
case 2: case 2:
ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
"%s%c %.12s %x", dsp->name, *region_name, "%s%c %.12s %x", dsp->name, *region_name,
wm_adsp_fw_text[dsp->fw], alg_region->alg); wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg);
break; break;
default: default:
ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
"%s %.12s %x", dsp->name, "%s %.12s %x", dsp->name,
wm_adsp_fw_text[dsp->fw], alg_region->alg); wm_adsp_fw_text[dsp->fw], cs_ctl->alg_region.alg);
break; break;
} }
if (subname) { if (cs_ctl->subname) {
int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
int skip = 0; int skip = 0;
...@@ -1472,30 +1445,81 @@ static int cs_dsp_create_control(struct wm_adsp *dsp, ...@@ -1472,30 +1445,81 @@ static int cs_dsp_create_control(struct wm_adsp *dsp,
avail -= strlen(dsp->component->name_prefix) + 1; avail -= strlen(dsp->component->name_prefix) + 1;
/* Truncate the subname from the start if it is too long */ /* Truncate the subname from the start if it is too long */
if (subname_len > avail) if (cs_ctl->subname_len > avail)
skip = subname_len - avail; skip = cs_ctl->subname_len - avail;
snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, snprintf(name + ret, SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret,
" %.*s", subname_len - skip, subname + skip); " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip);
} }
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
if (!ctl) if (!ctl)
return -ENOMEM; return -ENOMEM;
ctl->fw_name = wm_adsp_fw_text[dsp->fw]; ctl->cs_ctl = cs_ctl;
ctl->alg_region = *alg_region;
ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
if (!ctl->name) { if (!ctl->name) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_ctl; goto err_ctl;
} }
if (subname) {
cs_ctl->priv = ctl;
INIT_WORK(&ctl->work, wm_adsp_ctl_work);
schedule_work(&ctl->work);
return 0;
err_ctl:
kfree(ctl);
return ret;
}
static void wm_adsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
{
struct wm_coeff_ctl *ctl = cs_ctl->priv;
cancel_work_sync(&ctl->work);
kfree(ctl->name);
kfree(ctl);
}
static int cs_dsp_create_control(struct wm_adsp *dsp,
const struct cs_dsp_alg_region *alg_region,
unsigned int offset, unsigned int len,
const char *subname, unsigned int subname_len,
unsigned int flags, unsigned int type)
{
struct cs_dsp_coeff_ctl *ctl;
int ret;
list_for_each_entry(ctl, &dsp->ctl_list, list) {
if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
ctl->alg_region.alg == alg_region->alg &&
ctl->alg_region.type == alg_region->type) {
if ((!subname && !ctl->subname) ||
(subname && !strncmp(ctl->subname, subname, ctl->subname_len))) {
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;
if (subname && dsp->fw_ver >= 2) {
ctl->subname_len = subname_len; ctl->subname_len = subname_len;
ctl->subname = kmemdup(subname, ctl->subname = kmemdup(subname,
strlen(subname) + 1, GFP_KERNEL); strlen(subname) + 1, GFP_KERNEL);
if (!ctl->subname) { if (!ctl->subname) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_ctl_name; goto err_ctl;
} }
} }
ctl->enabled = 1; ctl->enabled = 1;
...@@ -1514,18 +1538,17 @@ static int cs_dsp_create_control(struct wm_adsp *dsp, ...@@ -1514,18 +1538,17 @@ static int cs_dsp_create_control(struct wm_adsp *dsp,
list_add(&ctl->list, &dsp->ctl_list); list_add(&ctl->list, &dsp->ctl_list);
if (flags & WMFW_CTL_FLAG_SYS) ret = wm_adsp_control_add(ctl);
return 0; if (ret)
goto err_list_del;
INIT_WORK(&ctl->work, wm_adsp_ctl_work);
schedule_work(&ctl->work);
return 0; return 0;
err_list_del:
list_del(&ctl->list);
kfree(ctl->cache);
err_ctl_subname: err_ctl_subname:
kfree(ctl->subname); kfree(ctl->subname);
err_ctl_name:
kfree(ctl->name);
err_ctl: err_ctl:
kfree(ctl); kfree(ctl);
...@@ -2013,14 +2036,14 @@ static int cs_dsp_load(struct wm_adsp *dsp) ...@@ -2013,14 +2036,14 @@ static int cs_dsp_load(struct wm_adsp *dsp)
} }
/* /*
* Find wm_coeff_ctl with input name as its subname * Find cs_dsp_coeff_ctl with input name as its subname
* If not found, return NULL * If not found, return NULL
*/ */
static struct wm_coeff_ctl *cs_dsp_get_ctl(struct wm_adsp *dsp, static struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct wm_adsp *dsp,
const char *name, int type, const char *name, int type,
unsigned int alg) unsigned int alg)
{ {
struct wm_coeff_ctl *pos, *rslt = NULL; struct cs_dsp_coeff_ctl *pos, *rslt = NULL;
const char *fw_txt = wm_adsp_fw_text[dsp->fw]; const char *fw_txt = wm_adsp_fw_text[dsp->fw];
list_for_each_entry(pos, &dsp->ctl_list, list) { list_for_each_entry(pos, &dsp->ctl_list, list) {
...@@ -2041,23 +2064,26 @@ static struct wm_coeff_ctl *cs_dsp_get_ctl(struct wm_adsp *dsp, ...@@ -2041,23 +2064,26 @@ static struct wm_coeff_ctl *cs_dsp_get_ctl(struct wm_adsp *dsp,
int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len) unsigned int alg, void *buf, size_t len)
{ {
struct cs_dsp_coeff_ctl *cs_ctl;
struct wm_coeff_ctl *ctl; struct wm_coeff_ctl *ctl;
struct snd_kcontrol *kcontrol; struct snd_kcontrol *kcontrol;
char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int ret; int ret;
ctl = cs_dsp_get_ctl(dsp, name, type, alg); cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg);
if (!ctl) if (!cs_ctl)
return -EINVAL; return -EINVAL;
if (len > ctl->len) ctl = cs_ctl->priv;
if (len > cs_ctl->len)
return -EINVAL; return -EINVAL;
ret = cs_dsp_coeff_write_ctrl(ctl, buf, len); ret = cs_dsp_coeff_write_ctrl(cs_ctl, buf, len);
if (ret) if (ret)
return ret; return ret;
if (ctl->flags & WMFW_CTL_FLAG_SYS) if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
return 0; return 0;
if (dsp->component->name_prefix) if (dsp->component->name_prefix)
...@@ -2083,23 +2109,23 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); ...@@ -2083,23 +2109,23 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type, int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len) unsigned int alg, void *buf, size_t len)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *cs_ctl;
ctl = cs_dsp_get_ctl(dsp, name, type, alg); cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg);
if (!ctl) if (!cs_ctl)
return -EINVAL; return -EINVAL;
if (len > ctl->len) if (len > cs_ctl->len)
return -EINVAL; return -EINVAL;
return cs_dsp_coeff_read_ctrl(ctl, buf, len); return cs_dsp_coeff_read_ctrl(cs_ctl, buf, len);
} }
EXPORT_SYMBOL_GPL(wm_adsp_read_ctl); EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
static void cs_dsp_ctl_fixup_base(struct wm_adsp *dsp, static void cs_dsp_ctl_fixup_base(struct wm_adsp *dsp,
const struct cs_dsp_alg_region *alg_region) const struct cs_dsp_alg_region *alg_region)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *ctl;
list_for_each_entry(ctl, &dsp->ctl_list, list) { list_for_each_entry(ctl, &dsp->ctl_list, list) {
if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] && if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] &&
...@@ -2885,7 +2911,7 @@ static int cs_dsp_adsp1_power_up(struct wm_adsp *dsp) ...@@ -2885,7 +2911,7 @@ static int cs_dsp_adsp1_power_up(struct wm_adsp *dsp)
static void cs_dsp_adsp1_power_down(struct wm_adsp *dsp) static void cs_dsp_adsp1_power_down(struct wm_adsp *dsp)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *ctl;
mutex_lock(&dsp->pwr_lock); mutex_lock(&dsp->pwr_lock);
...@@ -3199,7 +3225,7 @@ static void cs_dsp_power_up(struct wm_adsp *dsp) ...@@ -3199,7 +3225,7 @@ static void cs_dsp_power_up(struct wm_adsp *dsp)
static void cs_dsp_power_down(struct wm_adsp *dsp) static void cs_dsp_power_down(struct wm_adsp *dsp)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *ctl;
mutex_lock(&dsp->pwr_lock); mutex_lock(&dsp->pwr_lock);
...@@ -3496,11 +3522,13 @@ EXPORT_SYMBOL_GPL(wm_halo_init); ...@@ -3496,11 +3522,13 @@ EXPORT_SYMBOL_GPL(wm_halo_init);
static void cs_dsp_remove(struct wm_adsp *dsp) static void cs_dsp_remove(struct wm_adsp *dsp)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *ctl;
while (!list_empty(&dsp->ctl_list)) { while (!list_empty(&dsp->ctl_list)) {
ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl, ctl = list_first_entry(&dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
list);
wm_adsp_control_remove(ctl);
list_del(&ctl->list); list_del(&ctl->list);
cs_dsp_free_ctl_blk(ctl); cs_dsp_free_ctl_blk(ctl);
} }
...@@ -3936,15 +3964,16 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp) ...@@ -3936,15 +3964,16 @@ static int wm_adsp_buffer_parse_legacy(struct wm_adsp *dsp)
return 0; return 0;
} }
static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) 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_host_buf_coeff_v1 coeff_v1;
struct wm_adsp_compr_buf *buf; struct wm_adsp_compr_buf *buf;
struct wm_adsp *dsp = cs_ctl->dsp;
unsigned int version; unsigned int version;
int ret, i; int ret, i;
for (i = 0; i < 5; ++i) { for (i = 0; i < 5; ++i) {
ret = cs_dsp_coeff_read_ctrl(ctl, &coeff_v1, sizeof(coeff_v1)); ret = cs_dsp_coeff_read_ctrl(cs_ctl, &coeff_v1, sizeof(coeff_v1));
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -3955,15 +3984,15 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) ...@@ -3955,15 +3984,15 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
} }
if (!coeff_v1.host_buf_ptr) { if (!coeff_v1.host_buf_ptr) {
adsp_err(ctl->dsp, "Failed to acquire host buffer\n"); adsp_err(dsp, "Failed to acquire host buffer\n");
return -EIO; return -EIO;
} }
buf = wm_adsp_buffer_alloc(ctl->dsp); buf = wm_adsp_buffer_alloc(dsp);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
buf->host_buf_mem_type = ctl->alg_region.type; buf->host_buf_mem_type = cs_ctl->alg_region.type;
buf->host_buf_ptr = be32_to_cpu(coeff_v1.host_buf_ptr); buf->host_buf_ptr = be32_to_cpu(coeff_v1.host_buf_ptr);
ret = wm_adsp_buffer_populate(buf); ret = wm_adsp_buffer_populate(buf);
...@@ -3974,7 +4003,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) ...@@ -3974,7 +4003,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
* v0 host_buffer coefficients didn't have versioning, so if the * v0 host_buffer coefficients didn't have versioning, so if the
* control is one word, assume version 0. * control is one word, assume version 0.
*/ */
if (ctl->len == 4) { if (cs_ctl->len == 4) {
compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr); compr_dbg(buf, "host_buf_ptr=%x\n", buf->host_buf_ptr);
return 0; return 0;
} }
...@@ -3983,7 +4012,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) ...@@ -3983,7 +4012,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT; version >>= HOST_BUF_COEFF_COMPAT_VER_SHIFT;
if (version > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) { if (version > HOST_BUF_COEFF_SUPPORTED_COMPAT_VER) {
adsp_err(ctl->dsp, adsp_err(dsp,
"Host buffer coeff ver %u > supported version %u\n", "Host buffer coeff ver %u > supported version %u\n",
version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER); version, HOST_BUF_COEFF_SUPPORTED_COMPAT_VER);
return -EINVAL; return -EINVAL;
...@@ -3991,7 +4020,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) ...@@ -3991,7 +4020,7 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
cs_dsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name)); cs_dsp_remove_padding((u32 *)&coeff_v1.name, ARRAY_SIZE(coeff_v1.name));
buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", ctl->dsp->part, buf->name = kasprintf(GFP_KERNEL, "%s-dsp-%s", dsp->part,
(char *)&coeff_v1.name); (char *)&coeff_v1.name);
compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n", compr_dbg(buf, "host_buf_ptr=%x coeff version %u\n",
...@@ -4002,17 +4031,17 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl) ...@@ -4002,17 +4031,17 @@ static int wm_adsp_buffer_parse_coeff(struct wm_coeff_ctl *ctl)
static int wm_adsp_buffer_init(struct wm_adsp *dsp) static int wm_adsp_buffer_init(struct wm_adsp *dsp)
{ {
struct wm_coeff_ctl *ctl; struct cs_dsp_coeff_ctl *cs_ctl;
int ret; int ret;
list_for_each_entry(ctl, &dsp->ctl_list, list) { list_for_each_entry(cs_ctl, &dsp->ctl_list, list) {
if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER) if (cs_ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
continue; continue;
if (!ctl->enabled) if (!cs_ctl->enabled)
continue; continue;
ret = wm_adsp_buffer_parse_coeff(ctl); ret = wm_adsp_buffer_parse_coeff(cs_ctl);
if (ret < 0) { if (ret < 0) {
adsp_err(dsp, "Failed to parse coeff: %d\n", ret); adsp_err(dsp, "Failed to parse coeff: %d\n", ret);
goto error; goto error;
......
...@@ -49,10 +49,30 @@ struct cs_dsp_alg_region { ...@@ -49,10 +49,30 @@ struct cs_dsp_alg_region {
unsigned int base; unsigned int base;
}; };
struct wm_adsp;
struct wm_adsp_compr; struct wm_adsp_compr;
struct wm_adsp_compr_buf; struct wm_adsp_compr_buf;
struct cs_dsp_ops; struct cs_dsp_ops;
struct cs_dsp_coeff_ctl {
const char *fw_name;
/* Subname is needed to match with firmware */
const char *subname;
unsigned int subname_len;
struct cs_dsp_alg_region alg_region;
struct wm_adsp *dsp;
unsigned int enabled:1;
struct list_head list;
void *cache;
unsigned int offset;
size_t len;
unsigned int set:1;
unsigned int flags;
unsigned int type;
void *priv;
};
struct wm_adsp { struct wm_adsp {
const char *part; const char *part;
const char *name; const char *name;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment