diff mbox series

[v8,3/3] remoteproc: qcom: q6v5_wpss: Add support for sc7280 WPSS

Message ID 1635860673-12146-4-git-send-email-pillair@codeaurora.org (mailing list archive)
State Superseded
Headers show
Series Add support for sc7280 WPSS PIL loading | expand

Commit Message

Rakesh Pillai Nov. 2, 2021, 1:44 p.m. UTC
Add support for PIL loading of WPSS processor for SC7280
- WPSS boot will be requested by the wifi driver and hence
  disable auto-boot for WPSS.
- Add a separate shutdown sequence handler for WPSS.
- Add multiple power-domain voting support
- Parse firmware-name from dtsi entry

Signed-off-by: Rakesh Pillai <pillair@codeaurora.org>
---
 drivers/remoteproc/qcom_q6v5_adsp.c | 219 +++++++++++++++++++++++++++++++++---
 1 file changed, 203 insertions(+), 16 deletions(-)

Comments

Stephen Boyd Nov. 15, 2021, 11:43 p.m. UTC | #1
Quoting Rakesh Pillai (2021-11-02 06:44:33)
> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
> index 098362e6..e2e8d33 100644
> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> @@ -435,12 +571,22 @@ static int adsp_probe(struct platform_device *pdev)
>         if (!desc)
>                 return -EINVAL;
>
> +       firmware_name = desc->firmware_name;
> +       ret = of_property_read_string(pdev->dev.of_node, "firmware-name",

Is this documented in the binding? If not, please add it.

> +                                     &firmware_name);
> +       if (ret < 0 && ret != -EINVAL) {
> +               dev_err(&pdev->dev, "unable to read firmware-name\n");
> +               return ret;
> +       }
> +
>         rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
> -                           desc->firmware_name, sizeof(*adsp));
> +                           firmware_name, sizeof(*adsp));
>         if (!rproc) {
Rakesh Pillai Nov. 16, 2021, 5:49 p.m. UTC | #2
> -----Original Message-----
> From: Stephen Boyd <swboyd@chromium.org>
> Sent: Tuesday, November 16, 2021 5:13 AM
> To: Rakesh Pillai <pillair@codeaurora.org>; agross@kernel.org;
> bjorn.andersson@linaro.org; mathieu.poirier@linaro.org; ohad@wizery.com;
> p.zabel@pengutronix.de; robh+dt@kernel.org
> Cc: linux-arm-msm@vger.kernel.org; linux-remoteproc@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> sibis@codeaurora.org; mpubbise@codeaurora.org; kuabhs@chromium.org
> Subject: Re: [PATCH v8 3/3] remoteproc: qcom: q6v5_wpss: Add support for
> sc7280 WPSS
> 
> Quoting Rakesh Pillai (2021-11-02 06:44:33)
> > diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
> b/drivers/remoteproc/qcom_q6v5_adsp.c
> > index 098362e6..e2e8d33 100644
> > --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> > +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> > @@ -435,12 +571,22 @@ static int adsp_probe(struct platform_device
> *pdev)
> >         if (!desc)
> >                 return -EINVAL;
> >
> > +       firmware_name = desc->firmware_name;
> > +       ret = of_property_read_string(pdev->dev.of_node, "firmware-
> name",
> 
> Is this documented in the binding? If not, please add it.

Hi Stephen,
"firmware-name" is already documented in the bindings.

Thanks,
Rakesh Pillai.
Stephen Boyd Nov. 16, 2021, 10:54 p.m. UTC | #3
Quoting Rakesh Pillai (2021-11-02 06:44:33)
> @@ -457,7 +608,13 @@ static int adsp_probe(struct platform_device *pdev)
>         if (ret)
>                 goto free_rproc;
>
> -       pm_runtime_enable(adsp->dev);
> +       ret = qcom_rproc_pds_attach(adsp->dev, adsp->proxy_pds,
> +                                   desc->proxy_pd_names);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
> +               goto free_rproc;
> +       }
> +       adsp->proxy_pd_count = ret;

Can we check this against the define so that we don't have more than the
fixed number of power domains and try to access elements beyond the
length of the array?
Stephen Boyd Nov. 16, 2021, 11:53 p.m. UTC | #4
Quoting pillair@codeaurora.org (2021-11-16 09:49:05)
> >
> > Is this documented in the binding? If not, please add it.
>
> Hi Stephen,
> "firmware-name" is already documented in the bindings.
>

Ok I see it now. Thanks!
Rakesh Pillai Nov. 17, 2021, 6:31 a.m. UTC | #5
> -----Original Message-----
> From: Stephen Boyd <swboyd@chromium.org>
> Sent: Wednesday, November 17, 2021 4:25 AM
> To: Rakesh Pillai <pillair@codeaurora.org>; agross@kernel.org;
> bjorn.andersson@linaro.org; mathieu.poirier@linaro.org; ohad@wizery.com;
> p.zabel@pengutronix.de; robh+dt@kernel.org
> Cc: linux-arm-msm@vger.kernel.org; linux-remoteproc@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> sibis@codeaurora.org; mpubbise@codeaurora.org; kuabhs@chromium.org
> Subject: Re: [PATCH v8 3/3] remoteproc: qcom: q6v5_wpss: Add support for
> sc7280 WPSS
> 
> Quoting Rakesh Pillai (2021-11-02 06:44:33)
> > @@ -457,7 +608,13 @@ static int adsp_probe(struct platform_device
> *pdev)
> >         if (ret)
> >                 goto free_rproc;
> >
> > -       pm_runtime_enable(adsp->dev);
> > +       ret = qcom_rproc_pds_attach(adsp->dev, adsp->proxy_pds,
> > +                                   desc->proxy_pd_names);
> > +       if (ret < 0) {
> > +               dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
> > +               goto free_rproc;
> > +       }
> > +       adsp->proxy_pd_count = ret;
> 
> Can we check this against the define so that we don't have more than the
> fixed number of power domains and try to access elements beyond the
> length of the array?

The number of entries populated in the "proxy_pds" array depends on the "desc->proxy_pd_names", which is statically
initialized for each remoteproc. Hence there will not be any out of bound access for this array.

Thanks,
Rakesh Pillai.
Stephen Boyd Nov. 17, 2021, 6:39 a.m. UTC | #6
Quoting Rakesh Pillai (2021-11-16 22:31:51)
>
>
> > -----Original Message-----
> > From: Stephen Boyd <swboyd@chromium.org>
> > Sent: Wednesday, November 17, 2021 4:25 AM
> > To: Rakesh Pillai <pillair@codeaurora.org>; agross@kernel.org;
> > bjorn.andersson@linaro.org; mathieu.poirier@linaro.org; ohad@wizery.com;
> > p.zabel@pengutronix.de; robh+dt@kernel.org
> > Cc: linux-arm-msm@vger.kernel.org; linux-remoteproc@vger.kernel.org;
> > devicetree@vger.kernel.org; linux-kernel@vger.kernel.org;
> > sibis@codeaurora.org; mpubbise@codeaurora.org; kuabhs@chromium.org
> > Subject: Re: [PATCH v8 3/3] remoteproc: qcom: q6v5_wpss: Add support for
> > sc7280 WPSS
> >
> > Quoting Rakesh Pillai (2021-11-02 06:44:33)
> > > @@ -457,7 +608,13 @@ static int adsp_probe(struct platform_device
> > *pdev)
> > >         if (ret)
> > >                 goto free_rproc;
> > >
> > > -       pm_runtime_enable(adsp->dev);
> > > +       ret = qcom_rproc_pds_attach(adsp->dev, adsp->proxy_pds,
> > > +                                   desc->proxy_pd_names);
> > > +       if (ret < 0) {
> > > +               dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
> > > +               goto free_rproc;
> > > +       }
> > > +       adsp->proxy_pd_count = ret;
> >
> > Can we check this against the define so that we don't have more than the
> > fixed number of power domains and try to access elements beyond the
> > length of the array?
>
> The number of entries populated in the "proxy_pds" array depends on the "desc->proxy_pd_names", which is statically
> initialized for each remoteproc. Hence there will not be any out of bound access for this array.
>

Sure nothing is wrong today but it's a potential problem in the future
if someone adds more elements to proxy_pd_names than proxy_pds can hold.
Please prevent that from happening by writing stricter code.
diff mbox series

Patch

diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index 098362e6..e2e8d33 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -32,6 +32,7 @@ 
 
 /* time out value */
 #define ACK_TIMEOUT			1000
+#define ACK_TIMEOUT_US			1000000
 #define BOOT_FSM_TIMEOUT		10000
 /* mask values */
 #define EVB_MASK			GENMASK(27, 4)
@@ -51,6 +52,8 @@ 
 #define QDSP6SS_CORE_CBCR	0x20
 #define QDSP6SS_SLEEP_CBCR	0x3c
 
+#define QCOM_Q6V5_RPROC_PROXY_PD_MAX	3
+
 struct adsp_pil_data {
 	int crash_reason_smem;
 	const char *firmware_name;
@@ -58,9 +61,13 @@  struct adsp_pil_data {
 	const char *ssr_name;
 	const char *sysmon_name;
 	int ssctl_id;
+	bool is_wpss;
+	bool auto_boot;
 
 	const char **clk_ids;
 	int num_clks;
+	const char **proxy_pd_names;
+	const char *load_state;
 };
 
 struct qcom_adsp {
@@ -93,11 +100,143 @@  struct qcom_adsp {
 	void *mem_region;
 	size_t mem_size;
 
+	struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX];
+	size_t proxy_pd_count;
+
 	struct qcom_rproc_glink glink_subdev;
 	struct qcom_rproc_ssr ssr_subdev;
 	struct qcom_sysmon *sysmon;
+
+	int (*shutdown)(struct qcom_adsp *adsp);
 };
 
+static size_t qcom_rproc_pds_attach(struct device *dev, struct device **devs,
+				    const char **pd_names)
+{
+	size_t num_pds = 0;
+	int ret;
+	int i;
+
+	if (!pd_names)
+		return 0;
+
+	/* Handle single power domain */
+	if (dev->pm_domain) {
+		devs[0] = dev;
+		pm_runtime_enable(dev);
+		return 1;
+	}
+
+	while (pd_names[num_pds])
+		num_pds++;
+
+	for (i = 0; i < num_pds; i++) {
+		devs[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]);
+		if (IS_ERR_OR_NULL(devs[i])) {
+			ret = PTR_ERR(devs[i]) ? : -ENODATA;
+			goto unroll_attach;
+		}
+	}
+
+	return num_pds;
+
+unroll_attach:
+	for (i--; i >= 0; i--)
+		dev_pm_domain_detach(devs[i], false);
+
+	return ret;
+}
+
+static void qcom_rproc_pds_detach(struct qcom_adsp *adsp, struct device **pds,
+				  size_t pd_count)
+{
+	struct device *dev = adsp->dev;
+	int i;
+
+	/* Handle single power domain */
+	if (dev->pm_domain && pd_count) {
+		pm_runtime_disable(dev);
+		return;
+	}
+
+	for (i = 0; i < pd_count; i++)
+		dev_pm_domain_detach(pds[i], false);
+}
+
+static int qcom_rproc_pds_enable(struct qcom_adsp *adsp, struct device **pds,
+				 size_t pd_count)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < pd_count; i++) {
+		dev_pm_genpd_set_performance_state(pds[i], INT_MAX);
+		ret = pm_runtime_get_sync(pds[i]);
+		if (ret < 0) {
+			pm_runtime_put_noidle(pds[i]);
+			dev_pm_genpd_set_performance_state(pds[i], 0);
+			goto unroll_pd_votes;
+		}
+	}
+
+	return 0;
+
+unroll_pd_votes:
+	for (i--; i >= 0; i--) {
+		dev_pm_genpd_set_performance_state(pds[i], 0);
+		pm_runtime_put(pds[i]);
+	}
+
+	return ret;
+}
+
+static void qcom_rproc_pds_disable(struct qcom_adsp *adsp, struct device **pds,
+				   size_t pd_count)
+{
+	int i;
+
+	for (i = 0; i < pd_count; i++) {
+		dev_pm_genpd_set_performance_state(pds[i], 0);
+		pm_runtime_put(pds[i]);
+	}
+}
+
+static int qcom_wpss_shutdown(struct qcom_adsp *adsp)
+{
+	unsigned int val;
+
+	regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 1);
+
+	/* Wait for halt ACK from QDSP6 */
+	regmap_read_poll_timeout(adsp->halt_map,
+				 adsp->halt_lpass + LPASS_HALTACK_REG, val,
+				 val, 1000, ACK_TIMEOUT_US);
+
+	/* Assert the WPSS PDC Reset */
+	reset_control_assert(adsp->pdc_sync_reset);
+	/* Place the WPSS processor into reset */
+	reset_control_assert(adsp->restart);
+	/* wait after asserting subsystem restart from AOSS */
+	usleep_range(200, 205);
+	/* Remove the WPSS reset */
+	reset_control_deassert(adsp->restart);
+	/* De-assert the WPSS PDC Reset */
+	reset_control_deassert(adsp->pdc_sync_reset);
+
+	usleep_range(100, 105);
+
+	clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
+
+	regmap_write(adsp->halt_map, adsp->halt_lpass + LPASS_HALTREQ_REG, 0);
+
+	/* Wait for halt ACK from QDSP6 */
+	regmap_read_poll_timeout(adsp->halt_map,
+				 adsp->halt_lpass + LPASS_HALTACK_REG, val,
+				 !val, 1000, ACK_TIMEOUT_US);
+
+	return 0;
+}
+
 static int qcom_adsp_shutdown(struct qcom_adsp *adsp)
 {
 	unsigned long timeout;
@@ -193,12 +332,10 @@  static int adsp_start(struct rproc *rproc)
 	if (ret)
 		goto disable_irqs;
 
-	dev_pm_genpd_set_performance_state(adsp->dev, INT_MAX);
-	ret = pm_runtime_get_sync(adsp->dev);
-	if (ret) {
-		pm_runtime_put_noidle(adsp->dev);
+	ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds,
+				    adsp->proxy_pd_count);
+	if (ret < 0)
 		goto disable_xo_clk;
-	}
 
 	ret = clk_bulk_prepare_enable(adsp->num_clks, adsp->clks);
 	if (ret) {
@@ -243,8 +380,7 @@  static int adsp_start(struct rproc *rproc)
 disable_adsp_clks:
 	clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks);
 disable_power_domain:
-	dev_pm_genpd_set_performance_state(adsp->dev, 0);
-	pm_runtime_put(adsp->dev);
+	qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 disable_xo_clk:
 	clk_disable_unprepare(adsp->xo);
 disable_irqs:
@@ -258,8 +394,7 @@  static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5)
 	struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
 
 	clk_disable_unprepare(adsp->xo);
-	dev_pm_genpd_set_performance_state(adsp->dev, 0);
-	pm_runtime_put(adsp->dev);
+	qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 }
 
 static int adsp_stop(struct rproc *rproc)
@@ -272,7 +407,7 @@  static int adsp_stop(struct rproc *rproc)
 	if (ret == -ETIMEDOUT)
 		dev_err(adsp->dev, "timed out on wait\n");
 
-	ret = qcom_adsp_shutdown(adsp);
+	ret = adsp->shutdown(adsp);
 	if (ret)
 		dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
 
@@ -427,6 +562,7 @@  static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
 static int adsp_probe(struct platform_device *pdev)
 {
 	const struct adsp_pil_data *desc;
+	const char *firmware_name;
 	struct qcom_adsp *adsp;
 	struct rproc *rproc;
 	int ret;
@@ -435,12 +571,22 @@  static int adsp_probe(struct platform_device *pdev)
 	if (!desc)
 		return -EINVAL;
 
+	firmware_name = desc->firmware_name;
+	ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
+				      &firmware_name);
+	if (ret < 0 && ret != -EINVAL) {
+		dev_err(&pdev->dev, "unable to read firmware-name\n");
+		return ret;
+	}
+
 	rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
-			    desc->firmware_name, sizeof(*adsp));
+			    firmware_name, sizeof(*adsp));
 	if (!rproc) {
 		dev_err(&pdev->dev, "unable to allocate remoteproc\n");
 		return -ENOMEM;
 	}
+
+	rproc->auto_boot = desc->auto_boot;
 	rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
 
 	adsp = (struct qcom_adsp *)rproc->priv;
@@ -449,6 +595,11 @@  static int adsp_probe(struct platform_device *pdev)
 	adsp->info_name = desc->sysmon_name;
 	platform_set_drvdata(pdev, adsp);
 
+	if (desc->is_wpss)
+		adsp->shutdown = qcom_wpss_shutdown;
+	else
+		adsp->shutdown = qcom_adsp_shutdown;
+
 	ret = adsp_alloc_memory_region(adsp);
 	if (ret)
 		goto free_rproc;
@@ -457,7 +608,13 @@  static int adsp_probe(struct platform_device *pdev)
 	if (ret)
 		goto free_rproc;
 
-	pm_runtime_enable(adsp->dev);
+	ret = qcom_rproc_pds_attach(adsp->dev, adsp->proxy_pds,
+				    desc->proxy_pd_names);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
+		goto free_rproc;
+	}
+	adsp->proxy_pd_count = ret;
 
 	ret = adsp_init_reset(adsp);
 	if (ret)
@@ -467,8 +624,8 @@  static int adsp_probe(struct platform_device *pdev)
 	if (ret)
 		goto disable_pm;
 
-	ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, NULL,
-			     qcom_adsp_pil_handover);
+	ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem,
+			     desc->load_state, qcom_adsp_pil_handover);
 	if (ret)
 		goto disable_pm;
 
@@ -489,7 +646,8 @@  static int adsp_probe(struct platform_device *pdev)
 	return 0;
 
 disable_pm:
-	pm_runtime_disable(adsp->dev);
+	qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
+
 free_rproc:
 	rproc_free(rproc);
 
@@ -506,7 +664,7 @@  static int adsp_remove(struct platform_device *pdev)
 	qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
 	qcom_remove_sysmon_subdev(adsp->sysmon);
 	qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
-	pm_runtime_disable(adsp->dev);
+	qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 	rproc_free(adsp->rproc);
 
 	return 0;
@@ -518,11 +676,16 @@  static const struct adsp_pil_data adsp_resource_init = {
 	.ssr_name = "lpass",
 	.sysmon_name = "adsp",
 	.ssctl_id = 0x14,
+	.is_wpss = false,
+	.auto_boot = true,
 	.clk_ids = (const char*[]) {
 		"sway_cbcr", "lpass_ahbs_aon_cbcr", "lpass_ahbm_aon_cbcr",
 		"qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL
 	},
 	.num_clks = 7,
+	.proxy_pd_names = (const char*[]) {
+		"cx", NULL
+	},
 };
 
 static const struct adsp_pil_data cdsp_resource_init = {
@@ -531,15 +694,39 @@  static const struct adsp_pil_data cdsp_resource_init = {
 	.ssr_name = "cdsp",
 	.sysmon_name = "cdsp",
 	.ssctl_id = 0x17,
+	.is_wpss = false,
+	.auto_boot = true,
 	.clk_ids = (const char*[]) {
 		"sway", "tbu", "bimc", "ahb_aon", "q6ss_slave", "q6ss_master",
 		"q6_axim", NULL
 	},
 	.num_clks = 7,
+	.proxy_pd_names = (const char*[]) {
+		"cx", NULL
+	},
+};
+
+static const struct adsp_pil_data wpss_resource_init = {
+	.crash_reason_smem = 626,
+	.firmware_name = "wpss.mdt",
+	.ssr_name = "wpss",
+	.sysmon_name = "wpss",
+	.ssctl_id = 0x19,
+	.is_wpss = true,
+	.auto_boot = false,
+	.load_state = "wpss",
+	.clk_ids = (const char*[]) {
+		"ahb_bdg", "ahb", "rscp", NULL
+	},
+	.num_clks = 3,
+	.proxy_pd_names = (const char*[]) {
+		"cx", "mx", NULL
+	},
 };
 
 static const struct of_device_id adsp_of_match[] = {
 	{ .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init },
+	{ .compatible = "qcom,sc7280-wpss-pil", .data = &wpss_resource_init },
 	{ .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init },
 	{ },
 };