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

Commit 12c70cf9 authored by Tirupathi Reddy's avatar Tirupathi Reddy Committed by Taniya Das
Browse files

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



PBLs in current and future targets parse the MBA image format on
their own. Thus, all that is required for PIL is to load the MBA
as a blob instead of interpreting the ELF headers and loading
the one "LOAD" segment.

Change-Id: I9845c7059b6782b0802c462b4133ba8df814edd3
Signed-off-by: default avatarTirupathi Reddy <tirupath@codeaurora.org>
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent 0ff80c12
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -1201,7 +1201,7 @@
		vdd_pll-supply = <&pm8226_l8>;
		vdd_pll-supply = <&pm8226_l8>;
		qcom,vdd_pll = <1800000>;
		qcom,vdd_pll = <1800000>;


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


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


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


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


struct modem_pil_data {
struct modem_pil_data {
	struct mba_data image;
	struct modem_data image;
	const char *name;
	const char *name;
	u32 num_images;
	u32 num_images;
	u32 id;
	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];
		struct modem_pil_data *modem = &drv->modem[index];
		int img;
		int img;
		char *pmi_name = kzalloc((strlen(modem->name) + 5), GFP_KERNEL);
		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) {
		if (!pmi_name) {
			ret = -ENOMEM;
			ret = -ENOMEM;
@@ -522,7 +522,7 @@ static int pil_femto_modem_desc_probe(struct platform_device *pdev)
	struct modem_pil_data *modem;
	struct modem_pil_data *modem;
	struct pil_desc *mba_desc;
	struct pil_desc *mba_desc;
	struct resource *res;
	struct resource *res;
	struct mba_data *mba;
	struct modem_data *mba;
	void __iomem *rmb;
	void __iomem *rmb;
	int ret;
	int ret;
	u32 id;
	u32 id;
@@ -602,12 +602,13 @@ static int pil_femto_modem_desc_probe(struct platform_device *pdev)
	mba_desc = &mba->desc;
	mba_desc = &mba->desc;
	mba_desc->name = modem->name;
	mba_desc->name = modem->name;
	mba_desc->dev = dev;
	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->owner = THIS_MODULE;
	mba_desc->proxy_timeout = 0;
	mba_desc->proxy_timeout = 0;
	mba_desc->flags = skip_entry ? PIL_SKIP_ENTRY_CHECK : 0;
	mba_desc->flags = skip_entry ? PIL_SKIP_ENTRY_CHECK : 0;
	mba_desc->map_fw_mem = pil_femto_modem_map_fw_mem;
	mba_desc->map_fw_mem = pil_femto_modem_map_fw_mem;
	mba_desc->unmap_fw_mem = NULL;
	mba_desc->unmap_fw_mem = NULL;

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


	q6_desc = &q6->desc;
	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->owner = THIS_MODULE;
	q6_desc->proxy_timeout = 0;
	q6_desc->proxy_timeout = 0;
	q6_desc->map_fw_mem = pil_femto_modem_map_fw_mem;
	q6_desc->map_fw_mem = pil_femto_modem_map_fw_mem;
	q6_desc->unmap_fw_mem = NULL;
	q6_desc->unmap_fw_mem = NULL;


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


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


#include <linux/module.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/iopoll.h>
#include <linux/ioport.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;
static int modem_auth_timeout_ms = 10000;
module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
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;
	int ret = 0;
	struct device *dev = drv->desc.dev;
	u32 regval;
	u32 regval;


	if (drv->vreg) {
	if (drv->vreg) {
		ret = regulator_enable(drv->vreg);
		ret = regulator_enable(drv->vreg);
		if (ret)
		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) {
	if (drv->cxrail_bhs) {
@@ -91,7 +92,7 @@ static int pil_msa_pbl_power_up(struct q6v5_data *drv)
	return ret;
	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;
	u32 regval;


@@ -107,7 +108,7 @@ static int pil_msa_pbl_power_down(struct q6v5_data *drv)
	return 0;
	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;
	int ret;


@@ -131,7 +132,7 @@ err_ahb_clk:
	return ret;
	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->rom_clk);
	clk_disable_unprepare(drv->axi_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;
	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);
	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);
		writel_relaxed(1, drv->restart_reg);


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


	return 0;
	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);
	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
	phys_addr_t start_addr = pil_get_entry_addr(pil);
	phys_addr_t start_addr = pil_get_entry_addr(pil);
	int ret;
	int ret;


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

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


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


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


	/* Program Image Address */
	/* Program Image Address */
	if (drv->self_auth) {
	if (drv->self_auth) {
		writel_relaxed(start_addr, drv->rmb_base + RMB_MBA_IMAGE);
		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();
		mb();
	} else {
	} else {
		writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
		writel_relaxed((start_addr >> 4) & 0x0FFFFFF0,
@@ -248,68 +297,72 @@ static int pil_msa_pbl_reset(struct pil_desc *pil)
	return 0;
	return 0;


err_q6v5_reset:
err_q6v5_reset:
	pil_msa_pbl_disable_clks(drv);
	pil_mss_disable_clks(drv);
err_clks:
err_clks:
	if (drv->restart_reg)
	if (drv->restart_reg)
		writel_relaxed(1, drv->restart_reg);
		writel_relaxed(1, drv->restart_reg);
	pil_msa_pbl_power_down(drv);
	pil_mss_power_down(drv);
err_power:
err_power:
	return ret;
	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);
	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
	int uv = 0;
	char fw_name[30] = "mba.b00";

	const struct firmware *fw;
	ret = of_property_read_u32(pil->dev->of_node, "vdd_mx-uV", &uv);
	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) {
	if (ret) {
		dev_err(pil->dev, "missing vdd_mx-uV property\n");
		dev_err(pil->dev, "Failed to locate blob %s\n",
		return ret;
						fw_name);
		goto err_request_firmware;
	}
	}


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


	ret = regulator_enable(drv->vreg_mx);
	drv->mba_phys = mba_phys;
	if (ret) {
	drv->mba_virt = mba_virt;
		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);
	/* 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) {
	if (ret) {
		regulator_disable(drv->vreg_mx);
		dev_err(pil->dev, "MBA boot failed.\n");
		regulator_set_voltage(drv->vreg_mx, 0, INT_MAX);
		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)
	return 0;
{
	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);
}


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


static int pil_msa_mba_init_image(struct pil_desc *pil,
static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
				  const u8 *metadata, size_t size)
					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;
	void *mdata_virt;
	dma_addr_t mdata_phys;
	dma_addr_t mdata_phys;
	s32 status;
	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);
	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 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,
static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
				   size_t size)
				   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;
	s32 status;
	u32 img_length = readl_relaxed(drv->rmb_base + RMB_PMI_CODE_LENGTH);
	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)
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;
	int ret;
	s32 status;
	s32 status;


@@ -393,8 +457,37 @@ static int pil_msa_mba_auth(struct pil_desc *pil)
	return ret;
	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,
	.verify_blob = pil_msa_mba_verify_blob,
	.auth_and_reset = pil_msa_mba_auth,
	.auth_and_reset = pil_msa_mba_auth,
};
};
Loading