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

Commit 7624c281 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: pil-msa: Re-organize modem pil architecture"

parents 7648a880 12c70cf9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1209,7 +1209,7 @@
		vdd_pll-supply = <&pm8226_l8>;
		qcom,vdd_pll = <1800000>;

		qcom,firmware-name = "mba";
		qcom,firmware-name = "modem";
		qcom,pil-self-auth;

		/* GPIO inputs from mss */
+1 −1
Original line number Diff line number Diff line
@@ -878,7 +878,7 @@
		vdd_mx-uV = <1050000>;
		vdd_pll-supply = <&pm8110_l10>;
		qcom,vdd_pll = <1800000>;
		qcom,firmware-name = "mba";
		qcom,firmware-name = "modem";
		qcom,pil-self-auth;

		/* GPIO inputs from mss */
+1 −1
Original line number Diff line number Diff line
@@ -1990,7 +1990,7 @@
		vdd_mx-uV = <1050000>;
		vdd_pll-supply = <&pm8941_l12>;
		qcom,vdd_pll = <1800000>;
		qcom,firmware-name = "mba";
		qcom,firmware-name = "modem";
		qcom,pil-self-auth;

		/* GPIO inputs from mss */
+8 −7
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ static char *modem_status_str[MODEM_STATUS_LAST] = {
};

struct modem_pil_data {
	struct mba_data image;
	struct modem_data image;
	const char *name;
	u32 num_images;
	u32 id;
@@ -190,7 +190,7 @@ static int pil_femto_modem_start(struct femto_modem_data *drv)
		struct modem_pil_data *modem = &drv->modem[index];
		int img;
		char *pmi_name = kzalloc((strlen(modem->name) + 5), GFP_KERNEL);
		struct mba_data *image = &modem->image;
		struct modem_data *image = &modem->image;

		if (!pmi_name) {
			ret = -ENOMEM;
@@ -522,7 +522,7 @@ static int pil_femto_modem_desc_probe(struct platform_device *pdev)
	struct modem_pil_data *modem;
	struct pil_desc *mba_desc;
	struct resource *res;
	struct mba_data *mba;
	struct modem_data *mba;
	void __iomem *rmb;
	int ret;
	u32 id;
@@ -602,12 +602,13 @@ static int pil_femto_modem_desc_probe(struct platform_device *pdev)
	mba_desc = &mba->desc;
	mba_desc->name = modem->name;
	mba_desc->dev = dev;
	mba_desc->ops = &pil_msa_mba_ops;
	mba_desc->ops = &pil_msa_femto_mba_ops;
	mba_desc->owner = THIS_MODULE;
	mba_desc->proxy_timeout = 0;
	mba_desc->flags = skip_entry ? PIL_SKIP_ENTRY_CHECK : 0;
	mba_desc->map_fw_mem = pil_femto_modem_map_fw_mem;
	mba_desc->unmap_fw_mem = NULL;

	ret = pil_desc_init(mba_desc);
	if (ret)
		return ret;
@@ -673,15 +674,15 @@ static int pil_femto_modem_driver_probe(
	q6->self_auth = 1;

	q6_desc = &q6->desc;
	q6_desc->ops = &pil_msa_pbl_ops;
	q6_desc->ops = &pil_msa_mss_ops;
	q6_desc->owner = THIS_MODULE;
	q6_desc->proxy_timeout = 0;
	q6_desc->map_fw_mem = pil_femto_modem_map_fw_mem;
	q6_desc->unmap_fw_mem = NULL;

	/* For this target, PBL interactions are different. */
	pil_msa_pbl_ops.proxy_vote = NULL;
	pil_msa_pbl_ops.proxy_unvote = NULL;
	pil_msa_mss_ops.proxy_vote = NULL;
	pil_msa_mss_ops.proxy_unvote = NULL;

	/* Initialize the number of discovered modems. */
	drv->disc_modems = 0;
+151 −58
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
 */

#include <linux/module.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/ioport.h>
@@ -67,16 +69,15 @@ module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
static int modem_auth_timeout_ms = 10000;
module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);

static int pil_msa_pbl_power_up(struct q6v5_data *drv)
static int pil_mss_power_up(struct q6v5_data *drv)
{
	int ret = 0;
	struct device *dev = drv->desc.dev;
	u32 regval;

	if (drv->vreg) {
		ret = regulator_enable(drv->vreg);
		if (ret)
			dev_err(dev, "Failed to enable modem regulator.\n");
			dev_err(drv->desc.dev, "Failed to enable modem regulator.\n");
	}

	if (drv->cxrail_bhs) {
@@ -91,7 +92,7 @@ static int pil_msa_pbl_power_up(struct q6v5_data *drv)
	return ret;
}

static int pil_msa_pbl_power_down(struct q6v5_data *drv)
static int pil_mss_power_down(struct q6v5_data *drv)
{
	u32 regval;

@@ -107,7 +108,7 @@ static int pil_msa_pbl_power_down(struct q6v5_data *drv)
	return 0;
}

static int pil_msa_pbl_enable_clks(struct q6v5_data *drv)
static int pil_mss_enable_clks(struct q6v5_data *drv)
{
	int ret;

@@ -131,7 +132,7 @@ err_ahb_clk:
	return ret;
}

static void pil_msa_pbl_disable_clks(struct q6v5_data *drv)
static void pil_mss_disable_clks(struct q6v5_data *drv)
{
	clk_disable_unprepare(drv->rom_clk);
	clk_disable_unprepare(drv->axi_clk);
@@ -172,7 +173,7 @@ static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv)
	return 0;
}

static int pil_msa_pbl_shutdown(struct pil_desc *pil)
int pil_mss_shutdown(struct pil_desc *pil)
{
	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);

@@ -189,25 +190,70 @@ static int pil_msa_pbl_shutdown(struct pil_desc *pil)
		writel_relaxed(1, drv->restart_reg);

	if (drv->is_booted) {
		pil_msa_pbl_disable_clks(drv);
		pil_msa_pbl_power_down(drv);
		pil_mss_disable_clks(drv);
		pil_mss_power_down(drv);
		drv->is_booted = false;
	}

	return 0;
}

static int pil_msa_pbl_reset(struct pil_desc *pil)
int pil_mss_make_proxy_votes(struct pil_desc *pil)
{
	int ret;
	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
	int uv = 0;

	ret = of_property_read_u32(pil->dev->of_node, "vdd_mx-uV", &uv);
	if (ret) {
		dev_err(pil->dev, "missing vdd_mx-uV property\n");
		return ret;
	}

	ret = regulator_set_voltage(drv->vreg_mx, uv, INT_MAX);
	if (ret) {
		dev_err(pil->dev, "Failed to request vreg_mx voltage\n");
		return ret;
	}

	ret = regulator_enable(drv->vreg_mx);
	if (ret) {
		dev_err(pil->dev, "Failed to enable vreg_mx\n");
		regulator_set_voltage(drv->vreg_mx, 0, INT_MAX);
		return ret;
	}

	ret = pil_q6v5_make_proxy_votes(pil);
	if (ret) {
		regulator_disable(drv->vreg_mx);
		regulator_set_voltage(drv->vreg_mx, 0, INT_MAX);
	}

	return ret;
}

void pil_mss_remove_proxy_votes(struct pil_desc *pil)
{
	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
	pil_q6v5_remove_proxy_votes(pil);
	regulator_disable(drv->vreg_mx);
	regulator_set_voltage(drv->vreg_mx, 0, INT_MAX);
}

static int pil_mss_reset(struct pil_desc *pil)
{
	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
	phys_addr_t start_addr = pil_get_entry_addr(pil);
	int ret;

	if (drv->mba_phys)
		start_addr = drv->mba_phys;

	/*
	 * Bring subsystem out of reset and enable required
	 * regulators and clocks.
	 */
	ret = pil_msa_pbl_power_up(drv);
	ret = pil_mss_power_up(drv);
	if (ret)
		goto err_power;

@@ -218,14 +264,17 @@ static int pil_msa_pbl_reset(struct pil_desc *pil)
		udelay(2);
	}

	ret = pil_msa_pbl_enable_clks(drv);
	ret = pil_mss_enable_clks(drv);
	if (ret)
		goto err_clks;

	/* Program Image Address */
	if (drv->self_auth) {
		writel_relaxed(start_addr, drv->rmb_base + RMB_MBA_IMAGE);
		/* Ensure write to RMB base occurs before reset is released. */
		/*
		 * Ensure write to RMB base occurs before reset
		 * is released.
		 */
		mb();
	} else {
		writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
@@ -248,68 +297,72 @@ static int pil_msa_pbl_reset(struct pil_desc *pil)
	return 0;

err_q6v5_reset:
	pil_msa_pbl_disable_clks(drv);
	pil_mss_disable_clks(drv);
err_clks:
	if (drv->restart_reg)
		writel_relaxed(1, drv->restart_reg);
	pil_msa_pbl_power_down(drv);
	pil_mss_power_down(drv);
err_power:
	return ret;
}

static int pil_msa_pbl_make_proxy_votes(struct pil_desc *pil)
#define MBA_SIZE SZ_1M
int pil_mss_reset_load_mba(struct pil_desc *pil)
{
	int ret;
	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
	int uv = 0;

	ret = of_property_read_u32(pil->dev->of_node, "vdd_mx-uV", &uv);
	char fw_name[30] = "mba.b00";
	const struct firmware *fw;
	void *mba_virt;
	dma_addr_t mba_phys;
	int ret, count;
	const u8 *data;

	/* Load and authenticate mba image */
	ret = request_firmware(&fw, fw_name, pil->dev);
	if (ret) {
		dev_err(pil->dev, "missing vdd_mx-uV property\n");
		return ret;
		dev_err(pil->dev, "Failed to locate blob %s\n",
						fw_name);
		goto err_request_firmware;
	}

	ret = regulator_set_voltage(drv->vreg_mx, uv, INT_MAX);
	if (ret) {
		dev_err(pil->dev, "Failed to request vreg_mx voltage\n");
		return ret;
	mba_virt = dma_alloc_coherent(pil->dev, MBA_SIZE, &mba_phys,
					GFP_KERNEL);
	if (!mba_virt) {
		dev_err(pil->dev, "MBA metadata buffer allocation failed\n");
		goto err_mss_reset;
	}

	ret = regulator_enable(drv->vreg_mx);
	if (ret) {
		dev_err(pil->dev, "Failed to enable vreg_mx\n");
		regulator_set_voltage(drv->vreg_mx, 0, INT_MAX);
		return ret;
	}
	drv->mba_phys = mba_phys;
	drv->mba_virt = mba_virt;

	ret = pil_q6v5_make_proxy_votes(pil);
	/* Load the MBA image into memory */
	count = fw->size;
	data = fw ? fw->data : NULL;
	memcpy(mba_virt, data, count);
	wmb();

	ret = pil_mss_reset(pil);
	if (ret) {
		regulator_disable(drv->vreg_mx);
		regulator_set_voltage(drv->vreg_mx, 0, INT_MAX);
		dev_err(pil->dev, "MBA boot failed.\n");
		goto err_mss_reset;
	}

	return ret;
}
	/* The MBA doesn't run from DDR, free the memory now. */
	dma_free_coherent(pil->dev, MBA_SIZE, drv->mba_virt, drv->mba_phys);

static void pil_msa_pbl_remove_proxy_votes(struct pil_desc *pil)
{
	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
	pil_q6v5_remove_proxy_votes(pil);
	regulator_disable(drv->vreg_mx);
	regulator_set_voltage(drv->vreg_mx, 0, INT_MAX);
}
	return 0;

struct pil_reset_ops pil_msa_pbl_ops = {
	.proxy_vote = pil_msa_pbl_make_proxy_votes,
	.proxy_unvote = pil_msa_pbl_remove_proxy_votes,
	.auth_and_reset = pil_msa_pbl_reset,
	.shutdown = pil_msa_pbl_shutdown,
};
err_mss_reset:
	release_firmware(fw);
err_request_firmware:
	dma_free_coherent(pil->dev, MBA_SIZE, drv->mba_virt, drv->mba_phys);
	return ret;
}

static int pil_msa_mba_init_image(struct pil_desc *pil,
				  const u8 *metadata, size_t size)
static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
					size_t size)
{
	struct mba_data *drv = container_of(pil, struct mba_data, desc);
	struct modem_data *drv = dev_get_drvdata(pil->dev);
	void *mdata_virt;
	dma_addr_t mdata_phys;
	s32 status;
@@ -344,14 +397,25 @@ static int pil_msa_mba_init_image(struct pil_desc *pil,
	}

	dma_free_coherent(pil->dev, size, mdata_virt, mdata_phys);
	return ret;
}

static int pil_msa_mss_reset_mba_load_auth_mdt(struct pil_desc *pil,
				  const u8 *metadata, size_t size)
{
	int ret;

	ret = pil_mss_reset_load_mba(pil);
	if (ret)
		return ret;

	return pil_msa_auth_modem_mdt(pil, metadata, size);
}

static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
				   size_t size)
{
	struct mba_data *drv = container_of(pil, struct mba_data, desc);
	struct modem_data *drv = dev_get_drvdata(pil->dev);
	s32 status;
	u32 img_length = readl_relaxed(drv->rmb_base + RMB_PMI_CODE_LENGTH);

@@ -375,7 +439,7 @@ static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,

static int pil_msa_mba_auth(struct pil_desc *pil)
{
	struct mba_data *drv = container_of(pil, struct mba_data, desc);
	struct modem_data *drv = dev_get_drvdata(pil->dev);
	int ret;
	s32 status;

@@ -393,8 +457,37 @@ static int pil_msa_mba_auth(struct pil_desc *pil)
	return ret;
}

struct pil_reset_ops pil_msa_mba_ops = {
	.init_image = pil_msa_mba_init_image,
/*
 * To be used only if self-auth is disabled, or if the
 * MBA image is loaded as segments and not in init_image.
 */
struct pil_reset_ops pil_msa_mss_ops = {
	.proxy_vote = pil_mss_make_proxy_votes,
	.proxy_unvote = pil_mss_remove_proxy_votes,
	.auth_and_reset = pil_mss_reset,
	.shutdown = pil_mss_shutdown,
};

/*
 * To be used if self-auth is enabled and the MBA is to be loaded
 * in init_image and the modem headers are also to be authenticated
 * in init_image. Modem segments authenticated in auth_and_reset.
 */
struct pil_reset_ops pil_msa_mss_ops_selfauth = {
	.init_image = pil_msa_mss_reset_mba_load_auth_mdt,
	.proxy_vote = pil_mss_make_proxy_votes,
	.proxy_unvote = pil_mss_remove_proxy_votes,
	.verify_blob = pil_msa_mba_verify_blob,
	.auth_and_reset = pil_msa_mba_auth,
	.shutdown = pil_mss_shutdown,
};

/*
 * To be used if the modem headers are to be authenticated
 * in init_image, and the modem segments in auth_and_reset.
 */
struct pil_reset_ops pil_msa_femto_mba_ops = {
	.init_image = pil_msa_auth_modem_mdt,
	.verify_blob = pil_msa_mba_verify_blob,
	.auth_and_reset = pil_msa_mba_auth,
};
Loading