Commit b618a185 authored by Charles Keepax's avatar Charles Keepax Committed by Mark Brown

ASoC: wm_adsp: Split out adsp1 & 2 setup algorithms

The vast majority of the wm_adsp_setup_algs function is case statements
for ADSP1 or ADSP2, this patch splits this out into two separate
functions wm_adsp1_setup_algs and wm_adsp2_setup_algs. The small amount
of shared code between them is factored out into an extra helper
function. This makes the code a lot cleaner.
Signed-off-by: default avatarCharles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent b787f68c
...@@ -876,298 +876,295 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, ...@@ -876,298 +876,295 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
return ret; return ret;
} }
static int wm_adsp_setup_algs(struct wm_adsp *dsp) static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t algs,
unsigned int pos, unsigned int len)
{ {
struct regmap *regmap = dsp->regmap; void *alg;
struct wmfw_adsp1_id_hdr adsp1_id; int ret;
struct wmfw_adsp2_id_hdr adsp2_id;
struct wmfw_adsp1_alg_hdr *adsp1_alg;
struct wmfw_adsp2_alg_hdr *adsp2_alg;
void *alg, *buf;
struct wm_adsp_alg_region *region;
const struct wm_adsp_region *mem;
unsigned int pos, term;
size_t algs, buf_size;
__be32 val; __be32 val;
int i, ret;
switch (dsp->type) { if (algs == 0) {
case WMFW_ADSP1: adsp_err(dsp, "No algorithms\n");
mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); return ERR_PTR(-EINVAL);
break;
case WMFW_ADSP2:
mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
break;
default:
mem = NULL;
break;
} }
if (WARN_ON(!mem)) if (algs > 1024) {
return -EINVAL; adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
return ERR_PTR(-EINVAL);
}
switch (dsp->type) { /* Read the terminator first to validate the length */
case WMFW_ADSP1: ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
ret = regmap_raw_read(regmap, mem->base, &adsp1_id, if (ret != 0) {
sizeof(adsp1_id)); adsp_err(dsp, "Failed to read algorithm list end: %d\n",
if (ret != 0) { ret);
adsp_err(dsp, "Failed to read algorithm info: %d\n", return ERR_PTR(ret);
ret); }
return ret;
}
buf = &adsp1_id; if (be32_to_cpu(val) != 0xbedead)
buf_size = sizeof(adsp1_id); adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
pos + len, be32_to_cpu(val));
algs = be32_to_cpu(adsp1_id.algs); alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); if (!alg)
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", return ERR_PTR(-ENOMEM);
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,
algs);
region = kzalloc(sizeof(*region), GFP_KERNEL); ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
if (!region) if (ret != 0) {
return -ENOMEM; adsp_err(dsp, "Failed to read algorithm list: %d\n",
region->type = WMFW_ADSP1_ZM; ret);
region->alg = be32_to_cpu(adsp1_id.fw.id); kfree(alg);
region->base = be32_to_cpu(adsp1_id.zm); return ERR_PTR(ret);
list_add_tail(&region->list, &dsp->alg_regions); }
region = kzalloc(sizeof(*region), GFP_KERNEL); return alg;
if (!region) }
return -ENOMEM;
region->type = WMFW_ADSP1_DM;
region->alg = be32_to_cpu(adsp1_id.fw.id);
region->base = be32_to_cpu(adsp1_id.dm);
list_add_tail(&region->list, &dsp->alg_regions);
pos = sizeof(adsp1_id) / 2; static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
term = pos + ((sizeof(*adsp1_alg) * algs) / 2); {
break; struct wmfw_adsp1_id_hdr adsp1_id;
struct wmfw_adsp1_alg_hdr *adsp1_alg;
struct wm_adsp_alg_region *region;
const struct wm_adsp_region *mem;
unsigned int pos, len;
size_t algs;
int i, ret;
case WMFW_ADSP2: mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
ret = regmap_raw_read(regmap, mem->base, &adsp2_id, if (WARN_ON(!mem))
sizeof(adsp2_id)); return -EINVAL;
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm info: %d\n", ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
ret); sizeof(adsp1_id));
return ret; if (ret != 0) {
} adsp_err(dsp, "Failed to read algorithm info: %d\n",
ret);
return ret;
}
buf = &adsp2_id; algs = be32_to_cpu(adsp1_id.algs);
buf_size = sizeof(adsp2_id); 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,
algs);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP1_ZM;
region->alg = be32_to_cpu(adsp1_id.fw.id);
region->base = be32_to_cpu(adsp1_id.zm);
list_add_tail(&region->list, &dsp->alg_regions);
algs = be32_to_cpu(adsp2_id.algs); region = kzalloc(sizeof(*region), GFP_KERNEL);
dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); if (!region)
adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", return -ENOMEM;
dsp->fw_id, region->type = WMFW_ADSP1_DM;
(be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16, region->alg = be32_to_cpu(adsp1_id.fw.id);
(be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8, region->base = be32_to_cpu(adsp1_id.dm);
be32_to_cpu(adsp2_id.fw.ver) & 0xff, list_add_tail(&region->list, &dsp->alg_regions);
algs);
region = kzalloc(sizeof(*region), GFP_KERNEL); pos = sizeof(adsp1_id) / 2;
if (!region) len = (sizeof(*adsp1_alg) * algs) / 2;
return -ENOMEM;
region->type = WMFW_ADSP2_XM; adsp1_alg = wm_adsp_read_algs(dsp, algs, mem->base + pos, len);
region->alg = be32_to_cpu(adsp2_id.fw.id); if (IS_ERR(adsp1_alg))
region->base = be32_to_cpu(adsp2_id.xm); return PTR_ERR(adsp1_alg);
list_add_tail(&region->list, &dsp->alg_regions);
for (i = 0; i < algs; i++) {
adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
i, be32_to_cpu(adsp1_alg[i].alg.id),
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
be32_to_cpu(adsp1_alg[i].dm),
be32_to_cpu(adsp1_alg[i].zm));
region = kzalloc(sizeof(*region), GFP_KERNEL); region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region) if (!region) {
return -ENOMEM; ret = -ENOMEM;
region->type = WMFW_ADSP2_YM; goto out;
region->alg = be32_to_cpu(adsp2_id.fw.id); }
region->base = be32_to_cpu(adsp2_id.ym); region->type = WMFW_ADSP1_DM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].dm);
region->len = 0;
list_add_tail(&region->list, &dsp->alg_regions); list_add_tail(&region->list, &dsp->alg_regions);
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
region->len -= be32_to_cpu(adsp1_alg[i].dm);
region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id));
}
region = kzalloc(sizeof(*region), GFP_KERNEL); region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region) if (!region) {
return -ENOMEM; ret = -ENOMEM;
region->type = WMFW_ADSP2_ZM; goto out;
region->alg = be32_to_cpu(adsp2_id.fw.id); }
region->base = be32_to_cpu(adsp2_id.zm); region->type = WMFW_ADSP1_ZM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].zm);
region->len = 0;
list_add_tail(&region->list, &dsp->alg_regions); list_add_tail(&region->list, &dsp->alg_regions);
if (i + 1 < algs) {
pos = sizeof(adsp2_id) / 2; region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
term = pos + ((sizeof(*adsp2_alg) * algs) / 2); region->len -= be32_to_cpu(adsp1_alg[i].zm);
break; region->len *= 4;
wm_adsp_create_control(dsp, region);
default: } else {
WARN(1, "Unknown DSP type"); adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
return -EINVAL; be32_to_cpu(adsp1_alg[i].alg.id));
}
} }
if (algs == 0) { out:
adsp_err(dsp, "No algorithms\n"); kfree(adsp1_alg);
return -EINVAL; return ret;
} }
if (algs > 1024) { static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
adsp_err(dsp, "Algorithm count %zx excessive\n", algs); {
print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET, struct wmfw_adsp2_id_hdr adsp2_id;
buf, buf_size); struct wmfw_adsp2_alg_hdr *adsp2_alg;
struct wm_adsp_alg_region *region;
const struct wm_adsp_region *mem;
unsigned int pos, len;
size_t algs;
int i, ret;
mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
if (WARN_ON(!mem))
return -EINVAL; return -EINVAL;
}
/* Read the terminator first to validate the length */ ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val)); sizeof(adsp2_id));
if (ret != 0) { if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm list end: %d\n", adsp_err(dsp, "Failed to read algorithm info: %d\n",
ret); ret);
return ret; return ret;
} }
if (be32_to_cpu(val) != 0xbedead) algs = be32_to_cpu(adsp2_id.algs);
adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n", dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
term, be32_to_cpu(val)); adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
dsp->fw_id,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(adsp2_id.fw.ver) & 0xff,
algs);
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_XM;
region->alg = be32_to_cpu(adsp2_id.fw.id);
region->base = be32_to_cpu(adsp2_id.xm);
list_add_tail(&region->list, &dsp->alg_regions);
alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA); region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!alg) if (!region)
return -ENOMEM; return -ENOMEM;
region->type = WMFW_ADSP2_YM;
region->alg = be32_to_cpu(adsp2_id.fw.id);
region->base = be32_to_cpu(adsp2_id.ym);
list_add_tail(&region->list, &dsp->alg_regions);
ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2); region = kzalloc(sizeof(*region), GFP_KERNEL);
if (ret != 0) { if (!region)
adsp_err(dsp, "Failed to read algorithm list: %d\n", return -ENOMEM;
ret); region->type = WMFW_ADSP2_ZM;
goto out; region->alg = be32_to_cpu(adsp2_id.fw.id);
} region->base = be32_to_cpu(adsp2_id.zm);
list_add_tail(&region->list, &dsp->alg_regions);
adsp1_alg = alg; pos = sizeof(adsp2_id) / 2;
adsp2_alg = alg; len = (sizeof(*adsp2_alg) * algs) / 2;
for (i = 0; i < algs; i++) { adsp2_alg = wm_adsp_read_algs(dsp, algs, mem->base + pos, len);
switch (dsp->type) { if (IS_ERR(adsp2_alg))
case WMFW_ADSP1: return PTR_ERR(adsp2_alg);
adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
i, be32_to_cpu(adsp1_alg[i].alg.id),
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8,
be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff,
be32_to_cpu(adsp1_alg[i].dm),
be32_to_cpu(adsp1_alg[i].zm));
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region) {
ret = -ENOMEM;
goto out;
}
region->type = WMFW_ADSP1_DM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].dm);
region->len = 0;
list_add_tail(&region->list, &dsp->alg_regions);
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
region->len -= be32_to_cpu(adsp1_alg[i].dm);
region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id));
}
region = kzalloc(sizeof(*region), GFP_KERNEL); for (i = 0; i < algs; i++) {
if (!region) { adsp_info(dsp,
ret = -ENOMEM; "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
goto out; i, be32_to_cpu(adsp2_alg[i].alg.id),
} (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
region->type = WMFW_ADSP1_ZM; (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
region->alg = be32_to_cpu(adsp1_alg[i].alg.id); be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
region->base = be32_to_cpu(adsp1_alg[i].zm); be32_to_cpu(adsp2_alg[i].xm),
region->len = 0; be32_to_cpu(adsp2_alg[i].ym),
list_add_tail(&region->list, &dsp->alg_regions); be32_to_cpu(adsp2_alg[i].zm));
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
region->len -= be32_to_cpu(adsp1_alg[i].zm);
region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
be32_to_cpu(adsp1_alg[i].alg.id));
}
break;
case WMFW_ADSP2: region = kzalloc(sizeof(*region), GFP_KERNEL);
adsp_info(dsp, if (!region) {
"%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", ret = -ENOMEM;
i, be32_to_cpu(adsp2_alg[i].alg.id), goto out;
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, }
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, region->type = WMFW_ADSP2_XM;
be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
be32_to_cpu(adsp2_alg[i].xm), region->base = be32_to_cpu(adsp2_alg[i].xm);
be32_to_cpu(adsp2_alg[i].ym), region->len = 0;
be32_to_cpu(adsp2_alg[i].zm)); list_add_tail(&region->list, &dsp->alg_regions);
if (i + 1 < algs) {
region = kzalloc(sizeof(*region), GFP_KERNEL); region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
if (!region) { region->len -= be32_to_cpu(adsp2_alg[i].xm);
ret = -ENOMEM; region->len *= 4;
goto out; wm_adsp_create_control(dsp, region);
} } else {
region->type = WMFW_ADSP2_XM; adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
region->alg = be32_to_cpu(adsp2_alg[i].alg.id); be32_to_cpu(adsp2_alg[i].alg.id));
region->base = be32_to_cpu(adsp2_alg[i].xm); }
region->len = 0;
list_add_tail(&region->list, &dsp->alg_regions);
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
region->len -= be32_to_cpu(adsp2_alg[i].xm);
region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id));
}
region = kzalloc(sizeof(*region), GFP_KERNEL); region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region) { if (!region) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
region->type = WMFW_ADSP2_YM; region->type = WMFW_ADSP2_YM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id); region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].ym); region->base = be32_to_cpu(adsp2_alg[i].ym);
region->len = 0; region->len = 0;
list_add_tail(&region->list, &dsp->alg_regions); list_add_tail(&region->list, &dsp->alg_regions);
if (i + 1 < algs) { if (i + 1 < algs) {
region->len = be32_to_cpu(adsp2_alg[i + 1].ym); region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
region->len -= be32_to_cpu(adsp2_alg[i].ym); region->len -= be32_to_cpu(adsp2_alg[i].ym);
region->len *= 4; region->len *= 4;
wm_adsp_create_control(dsp, region); wm_adsp_create_control(dsp, region);
} else { } else {
adsp_warn(dsp, "Missing length info for region YM with ID %x\n", adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id)); be32_to_cpu(adsp2_alg[i].alg.id));
} }
region = kzalloc(sizeof(*region), GFP_KERNEL); region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region) { if (!region) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
region->type = WMFW_ADSP2_ZM; region->type = WMFW_ADSP2_ZM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id); region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].zm); region->base = be32_to_cpu(adsp2_alg[i].zm);
region->len = 0; region->len = 0;
list_add_tail(&region->list, &dsp->alg_regions); list_add_tail(&region->list, &dsp->alg_regions);
if (i + 1 < algs) { if (i + 1 < algs) {
region->len = be32_to_cpu(adsp2_alg[i + 1].zm); region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
region->len -= be32_to_cpu(adsp2_alg[i].zm); region->len -= be32_to_cpu(adsp2_alg[i].zm);
region->len *= 4; region->len *= 4;
wm_adsp_create_control(dsp, region); wm_adsp_create_control(dsp, region);
} else { } else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
be32_to_cpu(adsp2_alg[i].alg.id)); be32_to_cpu(adsp2_alg[i].alg.id));
}
break;
} }
} }
out: out:
kfree(alg); kfree(adsp2_alg);
return ret; return ret;
} }
...@@ -1410,7 +1407,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, ...@@ -1410,7 +1407,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
if (ret != 0) if (ret != 0)
goto err; goto err;
ret = wm_adsp_setup_algs(dsp); ret = wm_adsp1_setup_algs(dsp);
if (ret != 0) if (ret != 0)
goto err; goto err;
...@@ -1568,7 +1565,7 @@ static void wm_adsp2_boot_work(struct work_struct *work) ...@@ -1568,7 +1565,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
if (ret != 0) if (ret != 0)
goto err; goto err;
ret = wm_adsp_setup_algs(dsp); ret = wm_adsp2_setup_algs(dsp);
if (ret != 0) if (ret != 0)
goto err; goto err;
......
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