Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+248 −251
Original line number Diff line number Diff line
@@ -876,39 +876,65 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
	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)
{
	void *alg;
	int ret;
	__be32 val;

	if (algs == 0) {
		adsp_err(dsp, "No algorithms\n");
		return ERR_PTR(-EINVAL);
	}

	if (algs > 1024) {
		adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
		return ERR_PTR(-EINVAL);
	}

	/* Read the terminator first to validate the length */
	ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
	if (ret != 0) {
		adsp_err(dsp, "Failed to read algorithm list end: %d\n",
			ret);
		return ERR_PTR(ret);
	}

	if (be32_to_cpu(val) != 0xbedead)
		adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
			  pos + len, be32_to_cpu(val));

	alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA);
	if (!alg)
		return ERR_PTR(-ENOMEM);

	ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
	if (ret != 0) {
		adsp_err(dsp, "Failed to read algorithm list: %d\n",
			ret);
		kfree(alg);
		return ERR_PTR(ret);
	}

	return alg;
}

static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
{
	struct regmap *regmap = dsp->regmap;
	struct wmfw_adsp1_id_hdr adsp1_id;
	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;
	unsigned int pos, len;
	size_t algs;
	int i, ret;

	switch (dsp->type) {
	case WMFW_ADSP1:
	mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM);
		break;
	case WMFW_ADSP2:
		mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM);
		break;
	default:
		mem = NULL;
		break;
	}

	if (WARN_ON(!mem))
		return -EINVAL;

	switch (dsp->type) {
	case WMFW_ADSP1:
		ret = regmap_raw_read(regmap, mem->base, &adsp1_id,
	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp1_id,
			      sizeof(adsp1_id));
	if (ret != 0) {
		adsp_err(dsp, "Failed to read algorithm info: %d\n",
@@ -916,9 +942,6 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
		return ret;
	}

		buf = &adsp1_id;
		buf_size = sizeof(adsp1_id);

	algs = be32_to_cpu(adsp1_id.algs);
	dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
	adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
@@ -945,104 +968,13 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
	list_add_tail(&region->list, &dsp->alg_regions);

	pos = sizeof(adsp1_id) / 2;
		term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
		break;
	len = (sizeof(*adsp1_alg) * algs) / 2;

	case WMFW_ADSP2:
		ret = regmap_raw_read(regmap, mem->base, &adsp2_id,
				      sizeof(adsp2_id));
		if (ret != 0) {
			adsp_err(dsp, "Failed to read algorithm info: %d\n",
				 ret);
			return ret;
		}

		buf = &adsp2_id;
		buf_size = sizeof(adsp2_id);

		algs = be32_to_cpu(adsp2_id.algs);
		dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
		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);

		region = kzalloc(sizeof(*region), GFP_KERNEL);
		if (!region)
			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);

		region = kzalloc(sizeof(*region), GFP_KERNEL);
		if (!region)
			return -ENOMEM;
		region->type = WMFW_ADSP2_ZM;
		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);

		pos = sizeof(adsp2_id) / 2;
		term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
		break;

	default:
		WARN(1, "Unknown DSP type");
		return -EINVAL;
	}

	if (algs == 0) {
		adsp_err(dsp, "No algorithms\n");
		return -EINVAL;
	}

	if (algs > 1024) {
		adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
		print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
				     buf, buf_size);
		return -EINVAL;
	}

	/* Read the terminator first to validate the length */
	ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
	if (ret != 0) {
		adsp_err(dsp, "Failed to read algorithm list end: %d\n",
			ret);
		return ret;
	}

	if (be32_to_cpu(val) != 0xbedead)
		adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbeadead\n",
			  term, be32_to_cpu(val));

	alg = kzalloc((term - pos) * 2, GFP_KERNEL | GFP_DMA);
	if (!alg)
		return -ENOMEM;

	ret = regmap_raw_read(regmap, mem->base + pos, alg, (term - pos) * 2);
	if (ret != 0) {
		adsp_err(dsp, "Failed to read algorithm list: %d\n",
			ret);
		goto out;
	}

	adsp1_alg = alg;
	adsp2_alg = alg;
	adsp1_alg = wm_adsp_read_algs(dsp, algs, mem->base + pos, len);
	if (IS_ERR(adsp1_alg))
		return PTR_ERR(adsp1_alg);

	for (i = 0; i < algs; i++) {
		switch (dsp->type) {
		case WMFW_ADSP1:
		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,
@@ -1090,9 +1022,76 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
			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:
out:
	kfree(adsp1_alg);
	return ret;
}

static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
{
	struct wmfw_adsp2_id_hdr adsp2_id;
	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;

	ret = regmap_raw_read(dsp->regmap, mem->base, &adsp2_id,
			      sizeof(adsp2_id));
	if (ret != 0) {
		adsp_err(dsp, "Failed to read algorithm info: %d\n",
			 ret);
		return ret;
	}

	algs = be32_to_cpu(adsp2_id.algs);
	dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
	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);

	region = kzalloc(sizeof(*region), GFP_KERNEL);
	if (!region)
		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);

	region = kzalloc(sizeof(*region), GFP_KERNEL);
	if (!region)
		return -ENOMEM;
	region->type = WMFW_ADSP2_ZM;
	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);

	pos = sizeof(adsp2_id) / 2;
	len = (sizeof(*adsp2_alg) * algs) / 2;

	adsp2_alg = wm_adsp_read_algs(dsp, algs, mem->base + pos, len);
	if (IS_ERR(adsp2_alg))
		return PTR_ERR(adsp2_alg);

	for (i = 0; i < algs; i++) {
		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),
@@ -1162,12 +1161,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
			adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
				  be32_to_cpu(adsp2_alg[i].alg.id));
		}
			break;
		}
	}

out:
	kfree(alg);
	kfree(adsp2_alg);
	return ret;
}

@@ -1410,7 +1407,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
		if (ret != 0)
			goto err;

		ret = wm_adsp_setup_algs(dsp);
		ret = wm_adsp1_setup_algs(dsp);
		if (ret != 0)
			goto err;

@@ -1568,7 +1565,7 @@ static void wm_adsp2_boot_work(struct work_struct *work)
	if (ret != 0)
		goto err;

	ret = wm_adsp_setup_algs(dsp);
	ret = wm_adsp2_setup_algs(dsp);
	if (ret != 0)
		goto err;