Commit 471f4885 authored by Mark Brown's avatar Mark Brown

ASoC: wm_adsp: Implement support for algorithm-specific coefficient blocks

WMDR coefficient files can specify coefficients in terms of algorithm
specific data regions. Record the start addresses of these regions while
parsing the algorithms and then use them to handle coefficients with
these formats.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent d62f4bc6
...@@ -378,6 +378,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) ...@@ -378,6 +378,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
struct wmfw_adsp1_alg_hdr *adsp1_alg; struct wmfw_adsp1_alg_hdr *adsp1_alg;
struct wmfw_adsp2_alg_hdr *adsp2_alg; struct wmfw_adsp2_alg_hdr *adsp2_alg;
void *alg, *buf; void *alg, *buf;
struct wm_adsp_alg_region *region;
const struct wm_adsp_region *mem; const struct wm_adsp_region *mem;
unsigned int pos, term; unsigned int pos, term;
size_t algs, buf_size; size_t algs, buf_size;
...@@ -496,19 +497,80 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) ...@@ -496,19 +497,80 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
for (i = 0; i < algs; i++) { for (i = 0; i < algs; i++) {
switch (dsp->type) { switch (dsp->type) {
case WMFW_ADSP1: case WMFW_ADSP1:
adsp_info(dsp, "%d: ID %x v%d.%d.%d\n", adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n",
i, be32_to_cpu(adsp1_alg[i].alg.id), 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) & 0xff0000) >> 16,
(be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, (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].alg.ver) & 0xff,
be32_to_cpu(adsp1_alg[i].dm),
be32_to_cpu(adsp1_alg[i].zm));
if (adsp1_alg[i].dm) {
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP1_DM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].dm);
list_add_tail(&region->list,
&dsp->alg_regions);
}
if (adsp1_alg[i].zm) {
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP1_ZM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].zm);
list_add_tail(&region->list,
&dsp->alg_regions);
}
break; break;
case WMFW_ADSP2: case WMFW_ADSP2:
adsp_info(dsp, "%d: ID %x v%d.%d.%d\n", adsp_info(dsp,
"%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n",
i, be32_to_cpu(adsp2_alg[i].alg.id), i, be32_to_cpu(adsp2_alg[i].alg.id),
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16,
(be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8,
be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff); be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff,
be32_to_cpu(adsp2_alg[i].xm),
be32_to_cpu(adsp2_alg[i].ym),
be32_to_cpu(adsp2_alg[i].zm));
if (adsp2_alg[i].xm) {
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_XM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].xm);
list_add_tail(&region->list,
&dsp->alg_regions);
}
if (adsp2_alg[i].ym) {
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_YM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].ym);
list_add_tail(&region->list,
&dsp->alg_regions);
}
if (adsp2_alg[i].zm) {
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->type = WMFW_ADSP2_ZM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].zm);
list_add_tail(&region->list,
&dsp->alg_regions);
}
break; break;
} }
} }
...@@ -524,6 +586,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) ...@@ -524,6 +586,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
struct wmfw_coeff_hdr *hdr; struct wmfw_coeff_hdr *hdr;
struct wmfw_coeff_item *blk; struct wmfw_coeff_item *blk;
const struct firmware *firmware; const struct firmware *firmware;
const struct wm_adsp_region *mem;
struct wm_adsp_alg_region *alg_region;
const char *region_name; const char *region_name;
int ret, pos, blocks, type, offset, reg; int ret, pos, blocks, type, offset, reg;
char *file; char *file;
...@@ -588,6 +652,37 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) ...@@ -588,6 +652,37 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
region_name = "register"; region_name = "register";
reg = offset; reg = offset;
break; break;
case WMFW_ADSP1_DM:
case WMFW_ADSP1_ZM:
case WMFW_ADSP2_XM:
case WMFW_ADSP2_YM:
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));
mem = wm_adsp_find_region(dsp, type);
if (!mem) {
adsp_err(dsp, "No base for region %x\n", type);
break;
}
reg = 0;
list_for_each_entry(alg_region,
&dsp->alg_regions, list) {
if (le32_to_cpu(blk->id) == alg_region->alg &&
type == alg_region->type) {
reg = alg_region->base + offset;
reg = wm_adsp_region_to_reg(mem,
reg);
}
}
if (reg == 0)
adsp_err(dsp, "No %x for algorithm %x\n",
type, le32_to_cpu(blk->id));
break;
default: default:
adsp_err(dsp, "Unknown region type %x\n", type); adsp_err(dsp, "Unknown region type %x\n", type);
break; break;
...@@ -711,6 +806,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ...@@ -711,6 +806,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_soc_codec *codec = w->codec; struct snd_soc_codec *codec = w->codec;
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift]; struct wm_adsp *dsp = &dsps[w->shift];
struct wm_adsp_alg_region *alg_region;
unsigned int val; unsigned int val;
int ret; int ret;
...@@ -811,6 +907,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ...@@ -811,6 +907,14 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
"Failed to enable supply: %d\n", "Failed to enable supply: %d\n",
ret); ret);
} }
while (!list_empty(&dsp->alg_regions)) {
alg_region = list_first_entry(&dsp->alg_regions,
struct wm_adsp_alg_region,
list);
list_del(&alg_region->list);
kfree(alg_region);
}
break; break;
default: default:
...@@ -840,6 +944,8 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) ...@@ -840,6 +944,8 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
return ret; return ret;
} }
INIT_LIST_HEAD(&adsp->alg_regions);
if (dvfs) { if (dvfs) {
adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
if (IS_ERR(adsp->dvfs)) { if (IS_ERR(adsp->dvfs)) {
......
...@@ -25,6 +25,13 @@ struct wm_adsp_region { ...@@ -25,6 +25,13 @@ struct wm_adsp_region {
unsigned int base; unsigned int base;
}; };
struct wm_adsp_alg_region {
struct list_head list;
unsigned int alg;
int type;
unsigned int base;
};
struct wm_adsp { struct wm_adsp {
const char *part; const char *part;
int num; int num;
...@@ -34,6 +41,8 @@ struct wm_adsp { ...@@ -34,6 +41,8 @@ struct wm_adsp {
int base; int base;
struct list_head alg_regions;
const struct wm_adsp_region *mem; const struct wm_adsp_region *mem;
int num_mems; int num_mems;
......
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