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

Commit 75583416 authored by Olof Johansson's avatar Olof Johansson
Browse files

Merge tag 'v4.10-rockchip-drivers1' of...

Merge tag 'v4.10-rockchip-drivers1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into next/drivers

Changes to the power-domain driver including counter presets now being set
by firmware on the rk3399, avoiding infite loops when powering on/off a
domain and actually returning an error if power-domain addition fails.
The last part requires usage of the (new in 4.9-rc1) pm_genpd_remove
functionality as well.

* tag 'v4.10-rockchip-drivers1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip

:
  soc: rockchip: power-domain: Handle errors from of_genpd_add_provider_onecell
  soc: rockchip: power-domain: use pm_genpd_remove in error cleanup
  soc: rockchip: power-domain: avoid infinite loop
  soc: rockchip: power-domain: Don't (incorrectly) set rk3399 up/down counts

Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 26aec1f4 dabc0259
Loading
Loading
Loading
Loading
+63 −18
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
 */

#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/err.h>
#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
@@ -105,12 +106,24 @@ static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
	return (val & pd_info->idle_mask) == pd_info->idle_mask;
}

static unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu)
{
	unsigned int val;

	regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
	return val;
}

static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
					 bool idle)
{
	const struct rockchip_domain_info *pd_info = pd->info;
	struct generic_pm_domain *genpd = &pd->genpd;
	struct rockchip_pmu *pmu = pd->pmu;
	unsigned int target_ack;
	unsigned int val;
	bool is_idle;
	int ret;

	if (pd_info->req_mask == 0)
		return 0;
@@ -120,12 +133,26 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,

	dsb(sy);

	do {
		regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
	} while ((val & pd_info->ack_mask) != (idle ? pd_info->ack_mask : 0));
	/* Wait util idle_ack = 1 */
	target_ack = idle ? pd_info->ack_mask : 0;
	ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val,
					(val & pd_info->ack_mask) == target_ack,
					0, 10000);
	if (ret) {
		dev_err(pmu->dev,
			"failed to get ack on domain '%s', val=0x%x\n",
			genpd->name, val);
		return ret;
	}

	while (rockchip_pmu_domain_is_idle(pd) != idle)
		cpu_relax();
	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd,
					is_idle, is_idle == idle, 0, 10000);
	if (ret) {
		dev_err(pmu->dev,
			"failed to set idle on domain '%s', val=%d\n",
			genpd->name, is_idle);
		return ret;
	}

	return 0;
}
@@ -198,6 +225,8 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
					     bool on)
{
	struct rockchip_pmu *pmu = pd->pmu;
	struct generic_pm_domain *genpd = &pd->genpd;
	bool is_on;

	if (pd->info->pwr_mask == 0)
		return;
@@ -207,8 +236,13 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,

	dsb(sy);

	while (rockchip_pmu_domain_is_on(pd) != on)
		cpu_relax();
	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;
	}
}

static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
@@ -445,7 +479,16 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,

static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
{
	int i;
	int i, ret;

	/*
	 * We're in the error cleanup already, so we only complain,
	 * but won't emit another error on top of the original one.
	 */
	ret = pm_genpd_remove(&pd->genpd);
	if (ret < 0)
		dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",
			pd->genpd.name, ret);

	for (i = 0; i < pd->num_clks; i++) {
		clk_unprepare(pd->clks[i]);
@@ -597,8 +640,10 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev)
	 * Configure power up and down transition delays for CORE
	 * and GPU domains.
	 */
	if (pmu_info->core_power_transition_time)
		rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
					pmu_info->core_power_transition_time);
	if (pmu_info->gpu_pwrcnt_offset)
		rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
					pmu_info->gpu_power_transition_time);

@@ -627,7 +672,11 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev)
		goto err_out;
	}

	of_genpd_add_provider_onecell(np, &pmu->genpd_data);
	error = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
	if (error) {
		dev_err(dev, "failed to add provider: %d\n", error);
		goto err_out;
	}

	return 0;

@@ -722,11 +771,7 @@ static const struct rockchip_pmu_info rk3399_pmu = {
	.idle_offset = 0x64,
	.ack_offset = 0x68,

	.core_pwrcnt_offset = 0x9c,
	.gpu_pwrcnt_offset = 0xa4,

	.core_power_transition_time = 24,
	.gpu_power_transition_time = 24,
	/* ARM Trusted Firmware manages power transition times */

	.num_domains = ARRAY_SIZE(rk3399_pm_domains),
	.domain_info = rk3399_pm_domains,