Commit 200289db authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull pmdomain updates from Ulf Hansson:
 "pmdomain core:
   - Add support for s2idle for CPU PM domains on PREEMPT_RT
   - Add device managed version of dev_pm_domain_attach|detach_list()
   - Improve layout of the debugfs summary table

  pmdomain providers:
   - amlogic: Remove obsolete vpu domain driver
   - bcm: raspberrypi: Add support for devices used as wakeup-sources
   - imx: Fixup clock handling for imx93 at driver remove
   - rockchip: Add gating support for RK3576
   - rockchip: Add support for RK3576 SoC
   - Some OF parsing simplifications
   - Some simplifications by using dev_err_probe() and guard()

  pmdomain consumers:
   - qcom/media/venus: Convert to the device managed APIs for PM domains

  cpuidle-psci:
   - Add support for s2idle/s2ram for the hierarchical topology on
     PREEMPT_RT
   - Some OF parsing simplifications"

* tag 'pmdomain-v6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (39 commits)
  pmdomain: core: Reduce debug summary table width
  pmdomain: core: Move mode_status_str()
  pmdomain: core: Fix "managed by" alignment in debug summary
  pmdomain: core: Harden inter-column space in debug summary
  pmdomain: rockchip: Add gating masks for rk3576
  pmdomain: rockchip: Add gating support
  pmdomain: rockchip: Simplify dropping OF node reference
  pmdomain: mediatek: make use of dev_err_cast_probe()
  pmdomain: imx93-pd: drop the context variable "init_off"
  pmdomain: imx93-pd: don't unprepare clocks on driver remove
  pmdomain: imx93-pd: replace dev_err() with dev_err_probe()
  pmdomain: qcom: rpmpd: Simplify locking with guard()
  pmdomain: qcom: rpmhpd: Simplify locking with guard()
  pmdomain: qcom: cpr: Simplify locking with guard()
  pmdomain: qcom: cpr: Simplify with dev_err_probe()
  pmdomain: imx: gpcv2: Simplify with scoped for each OF child loop
  pmdomain: imx: gpc: Simplify with scoped for each OF child loop
  pmdomain: rockchip: SimplUlf Hanssonify locking with guard()
  pmdomain: rockchip: Simplify with scoped for each OF child loop
  pmdomain: qcom-cpr: Use scope based of_node_put() to simplify code.
  ...
parents 2fe3c78a c6ccb691
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ properties:
      - rockchip,rk3368-power-controller
      - rockchip,rk3399-power-controller
      - rockchip,rk3568-power-controller
      - rockchip,rk3576-power-controller
      - rockchip,rk3588-power-controller
      - rockchip,rv1126-power-controller

+45 −0
Original line number Diff line number Diff line
@@ -276,6 +276,51 @@ int dev_pm_domain_attach_list(struct device *dev,
}
EXPORT_SYMBOL_GPL(dev_pm_domain_attach_list);

/**
 * devm_pm_domain_detach_list - devres-enabled version of dev_pm_domain_detach_list.
 * @_list: The list of PM domains to detach.
 *
 * This function reverse the actions from devm_pm_domain_attach_list().
 * it will be invoked during the remove phase from drivers implicitly if driver
 * uses devm_pm_domain_attach_list() to attach the PM domains.
 */
static void devm_pm_domain_detach_list(void *_list)
{
	struct dev_pm_domain_list *list = _list;

	dev_pm_domain_detach_list(list);
}

/**
 * devm_pm_domain_attach_list - devres-enabled version of dev_pm_domain_attach_list
 * @dev: The device used to lookup the PM domains for.
 * @data: The data used for attaching to the PM domains.
 * @list: An out-parameter with an allocated list of attached PM domains.
 *
 * NOTE: this will also handle calling devm_pm_domain_detach_list() for
 * you during remove phase.
 *
 * Returns the number of attached PM domains or a negative error code in case of
 * a failure.
 */
int devm_pm_domain_attach_list(struct device *dev,
			       const struct dev_pm_domain_attach_data *data,
			       struct dev_pm_domain_list **list)
{
	int ret, num_pds;

	num_pds = dev_pm_domain_attach_list(dev, data, list);
	if (num_pds <= 0)
		return num_pds;

	ret = devm_add_action_or_reset(dev, devm_pm_domain_detach_list, *list);
	if (ret)
		return ret;

	return num_pds;
}
EXPORT_SYMBOL_GPL(devm_pm_domain_attach_list);

/**
 * dev_pm_domain_detach - Detach a device from its PM domain.
 * @dev: Device to detach.
+9 −8
Original line number Diff line number Diff line
@@ -67,12 +67,16 @@ static int psci_pd_init(struct device_node *np, bool use_osi)

	/*
	 * Allow power off when OSI has been successfully enabled.
	 * PREEMPT_RT is not yet ready to enter domain idle states.
	 * On a PREEMPT_RT based configuration the domain idle states are
	 * supported, but only during system-wide suspend.
	 */
	if (use_osi && !IS_ENABLED(CONFIG_PREEMPT_RT))
	if (use_osi) {
		pd->power_off = psci_pd_power_off;
	else
		if (IS_ENABLED(CONFIG_PREEMPT_RT))
			pd->flags |= GENPD_FLAG_RPM_ALWAYS_ON;
	} else {
		pd->flags |= GENPD_FLAG_ALWAYS_ON;
	}

	/* Use governor for CPU PM domains if it has some states to manage. */
	pd_gov = pd->states ? &pm_domain_cpu_gov : NULL;
@@ -138,7 +142,6 @@ static const struct of_device_id psci_of_match[] = {
static int psci_cpuidle_domain_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device_node *node;
	bool use_osi = psci_has_osi_support();
	int ret = 0, pd_count = 0;

@@ -149,15 +152,13 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
	 * Parse child nodes for the "#power-domain-cells" property and
	 * initialize a genpd/genpd-of-provider pair when it's found.
	 */
	for_each_child_of_node(np, node) {
	for_each_child_of_node_scoped(np, node) {
		if (!of_property_present(node, "#power-domain-cells"))
			continue;

		ret = psci_pd_init(node, use_osi);
		if (ret) {
			of_node_put(node);
		if (ret)
			goto exit;
		}

		pd_count++;
	}
+17 −9
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ struct psci_cpuidle_data {

static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data);
static DEFINE_PER_CPU(u32, domain_state);
static bool psci_cpuidle_use_syscore;
static bool psci_cpuidle_use_cpuhp;

void psci_set_domain_state(u32 state)
@@ -166,6 +167,12 @@ static struct syscore_ops psci_idle_syscore_ops = {
	.resume = psci_idle_syscore_resume,
};

static void psci_idle_init_syscore(void)
{
	if (psci_cpuidle_use_syscore)
		register_syscore_ops(&psci_idle_syscore_ops);
}

static void psci_idle_init_cpuhp(void)
{
	int err;
@@ -173,8 +180,6 @@ static void psci_idle_init_cpuhp(void)
	if (!psci_cpuidle_use_cpuhp)
		return;

	register_syscore_ops(&psci_idle_syscore_ops);

	err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING,
					"cpuidle/psci:online",
					psci_idle_cpuhp_up,
@@ -222,22 +227,23 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv,
	if (!psci_has_osi_support())
		return 0;

	if (IS_ENABLED(CONFIG_PREEMPT_RT))
		return 0;

	data->dev = dt_idle_attach_cpu(cpu, "psci");
	if (IS_ERR_OR_NULL(data->dev))
		return PTR_ERR_OR_ZERO(data->dev);

	psci_cpuidle_use_syscore = true;

	/*
	 * Using the deepest state for the CPU to trigger a potential selection
	 * of a shared state for the domain, assumes the domain states are all
	 * deeper states.
	 * deeper states. On PREEMPT_RT the hierarchical topology is limited to
	 * s2ram and s2idle.
	 */
	drv->states[state_count - 1].flags |= CPUIDLE_FLAG_RCU_IDLE;
	drv->states[state_count - 1].enter = psci_enter_domain_idle_state;
	drv->states[state_count - 1].enter_s2idle = psci_enter_s2idle_domain_idle_state;
	if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {
		drv->states[state_count - 1].enter = psci_enter_domain_idle_state;
		psci_cpuidle_use_cpuhp = true;
	}

	return 0;
}
@@ -313,6 +319,7 @@ static void psci_cpu_deinit_idle(int cpu)
	struct psci_cpuidle_data *data = per_cpu_ptr(&psci_cpuidle_data, cpu);

	dt_idle_detach_cpu(data->dev);
	psci_cpuidle_use_syscore = false;
	psci_cpuidle_use_cpuhp = false;
}

@@ -409,6 +416,7 @@ static int psci_cpuidle_probe(struct platform_device *pdev)
			goto out_fail;
	}

	psci_idle_init_syscore();
	psci_idle_init_cpuhp();
	return 0;

+4 −10
Original line number Diff line number Diff line
@@ -130,11 +130,10 @@ struct generic_pm_domain *dt_idle_pd_alloc(struct device_node *np,

int dt_idle_pd_init_topology(struct device_node *np)
{
	struct device_node *node;
	struct of_phandle_args child, parent;
	int ret;

	for_each_child_of_node(np, node) {
	for_each_child_of_node_scoped(np, node) {
		if (of_parse_phandle_with_args(node, "power-domains",
					"#power-domain-cells", 0, &parent))
			continue;
@@ -143,22 +142,19 @@ int dt_idle_pd_init_topology(struct device_node *np)
		child.args_count = 0;
		ret = of_genpd_add_subdomain(&parent, &child);
		of_node_put(parent.np);
		if (ret) {
			of_node_put(node);
		if (ret)
			return ret;
	}
	}

	return 0;
}

int dt_idle_pd_remove_topology(struct device_node *np)
{
	struct device_node *node;
	struct of_phandle_args child, parent;
	int ret;

	for_each_child_of_node(np, node) {
	for_each_child_of_node_scoped(np, node) {
		if (of_parse_phandle_with_args(node, "power-domains",
					"#power-domain-cells", 0, &parent))
			continue;
@@ -167,11 +163,9 @@ int dt_idle_pd_remove_topology(struct device_node *np)
		child.args_count = 0;
		ret = of_genpd_remove_subdomain(&parent, &child);
		of_node_put(parent.np);
		if (ret) {
			of_node_put(node);
		if (ret)
			return ret;
	}
	}

	return 0;
}
Loading