Commit 7ab6c930 authored by Sebastian Reichel's avatar Sebastian Reichel Committed by Ulf Hansson
Browse files

pmdomain: rockchip: forward rockchip_do_pmu_set_power_domain errors



Currently rockchip_do_pmu_set_power_domain prints a warning if there
have been errors turning on the power domain, but it does not return
any errors and rockchip_pd_power() tries to continue setting up the
QOS registers. This usually results in accessing unpowered registers,
which triggers an SError and a full system hang.

This improves the error handling by forwarding the error to avoid
kernel panics.

Reviewed-by: default avatarHeiko Stuebner <heiko@sntech.de>
Tested-by: default avatarHeiko Stuebner <heiko@sntech.de>
Tested-by: Adrian Larumbe <adrian.larumbe@collabora.com> # On Rock 5B
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
Link: https://lore.kernel.org/r/20250220-rk3588-gpu-pwr-domain-regulator-v6-3-a4f9c24e5b81@kernel.org


[Ulf: Fixed conflict when applying]
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 83b2fbac
Loading
Loading
Loading
Loading
+23 −12
Original line number Diff line number Diff line
@@ -535,7 +535,7 @@ static int rockchip_pmu_domain_mem_reset(struct rockchip_pm_domain *pd)
	return ret;
}

static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
static int rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
					    bool on)
{
	struct rockchip_pmu *pmu = pd->pmu;
@@ -543,9 +543,10 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
	u32 pd_pwr_offset = pd->info->pwr_offset;
	bool is_on, is_mem_on = false;
	struct arm_smccc_res res;
	int ret;

	if (pd->info->pwr_mask == 0)
		return;
		return 0;

	if (on && pd->info->mem_status_mask)
		is_mem_on = rockchip_pmu_domain_is_mem_on(pd);
@@ -560,15 +561,19 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,

	wmb();

	if (is_mem_on && rockchip_pmu_domain_mem_reset(pd))
		return;
	if (is_mem_on) {
		ret = rockchip_pmu_domain_mem_reset(pd);
		if (ret)
			return ret;
	}


	if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
				      is_on == on, 0, 10000)) {
		dev_err(pmu->dev,
			"failed to set domain '%s', val=%d\n",
			genpd->name, is_on);
		return;
	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
					is_on == on, 0, 10000);
	if (ret) {
		dev_err(pmu->dev, "failed to set domain '%s' %s, val=%d\n",
			genpd->name, on ? "on" : "off", is_on);
		return ret;
	}

	/* Inform firmware to keep this pd on or off */
@@ -576,6 +581,8 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
		arm_smccc_smc(ROCKCHIP_SIP_SUSPEND_MODE, ROCKCHIP_SLEEP_PD_CONFIG,
				pmu->info->pwr_offset + pd_pwr_offset,
				pd->info->pwr_mask, on, 0, 0, 0, &res);

	return 0;
}

static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
@@ -601,7 +608,11 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
			rockchip_pmu_set_idle_request(pd, true);
		}

		rockchip_do_pmu_set_power_domain(pd, power_on);
		ret = rockchip_do_pmu_set_power_domain(pd, power_on);
		if (ret < 0) {
			clk_bulk_disable(pd->num_clks, pd->clks);
			return ret;
		}

		if (power_on) {
			/* if powering up, leave idle mode */