static int cs_dsp_adsp2_setup_algs()

in cirrus/cs_dsp.c [1771:1904]


static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp)
{
	struct wmfw_adsp2_id_hdr adsp2_id;
	struct wmfw_adsp2_alg_hdr *adsp2_alg;
	struct cs_dsp_alg_region *alg_region;
	const struct cs_dsp_region *mem;
	unsigned int pos, len;
	size_t n_algs;
	int i, ret;

	mem = cs_dsp_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) {
		cs_dsp_err(dsp, "Failed to read algorithm info: %d\n",
			   ret);
		return ret;
	}

	n_algs = be32_to_cpu(adsp2_id.n_algs);

	cs_dsp_parse_wmfw_id_header(dsp, &adsp2_id.fw, n_algs);

	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
					  adsp2_id.fw.id, adsp2_id.fw.ver,
					  adsp2_id.xm);
	if (IS_ERR(alg_region))
		return PTR_ERR(alg_region);

	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
					  adsp2_id.fw.id, adsp2_id.fw.ver,
					  adsp2_id.ym);
	if (IS_ERR(alg_region))
		return PTR_ERR(alg_region);

	alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
					  adsp2_id.fw.id, adsp2_id.fw.ver,
					  adsp2_id.zm);
	if (IS_ERR(alg_region))
		return PTR_ERR(alg_region);

	/* Calculate offset and length in DSP words */
	pos = sizeof(adsp2_id) / sizeof(u32);
	len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);

	adsp2_alg = cs_dsp_read_algs(dsp, n_algs, mem, pos, len);
	if (IS_ERR(adsp2_alg))
		return PTR_ERR(adsp2_alg);

	for (i = 0; i < n_algs; i++) {
		cs_dsp_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),
			    (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) & 0xff,
			    be32_to_cpu(adsp2_alg[i].xm),
			    be32_to_cpu(adsp2_alg[i].ym),
			    be32_to_cpu(adsp2_alg[i].zm));

		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM,
						  adsp2_alg[i].alg.id,
						  adsp2_alg[i].alg.ver,
						  adsp2_alg[i].xm);
		if (IS_ERR(alg_region)) {
			ret = PTR_ERR(alg_region);
			goto out;
		}
		if (dsp->fw_ver == 0) {
			if (i + 1 < n_algs) {
				len = be32_to_cpu(adsp2_alg[i + 1].xm);
				len -= be32_to_cpu(adsp2_alg[i].xm);
				len *= 4;
				cs_dsp_create_control(dsp, alg_region, 0,
						      len, NULL, 0, 0,
						      WMFW_CTL_TYPE_BYTES);
			} else {
				cs_dsp_warn(dsp, "Missing length info for region XM with ID %x\n",
					    be32_to_cpu(adsp2_alg[i].alg.id));
			}
		}

		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_YM,
						  adsp2_alg[i].alg.id,
						  adsp2_alg[i].alg.ver,
						  adsp2_alg[i].ym);
		if (IS_ERR(alg_region)) {
			ret = PTR_ERR(alg_region);
			goto out;
		}
		if (dsp->fw_ver == 0) {
			if (i + 1 < n_algs) {
				len = be32_to_cpu(adsp2_alg[i + 1].ym);
				len -= be32_to_cpu(adsp2_alg[i].ym);
				len *= 4;
				cs_dsp_create_control(dsp, alg_region, 0,
						      len, NULL, 0, 0,
						      WMFW_CTL_TYPE_BYTES);
			} else {
				cs_dsp_warn(dsp, "Missing length info for region YM with ID %x\n",
					    be32_to_cpu(adsp2_alg[i].alg.id));
			}
		}

		alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_ZM,
						  adsp2_alg[i].alg.id,
						  adsp2_alg[i].alg.ver,
						  adsp2_alg[i].zm);
		if (IS_ERR(alg_region)) {
			ret = PTR_ERR(alg_region);
			goto out;
		}
		if (dsp->fw_ver == 0) {
			if (i + 1 < n_algs) {
				len = be32_to_cpu(adsp2_alg[i + 1].zm);
				len -= be32_to_cpu(adsp2_alg[i].zm);
				len *= 4;
				cs_dsp_create_control(dsp, alg_region, 0,
						      len, NULL, 0, 0,
						      WMFW_CTL_TYPE_BYTES);
			} else {
				cs_dsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
					    be32_to_cpu(adsp2_alg[i].alg.id));
			}
		}
	}

out:
	kfree(adsp2_alg);
	return ret;
}