mirror of
https://github.com/torvalds/linux.git
synced 2025-04-12 15:25:13 +00:00

When a clock-controller lists multiple power-domains we need make each GDSC a subdomain of each of the clock-controller's listed power-domains. GDSCs without an explicitly defined parent should be a subdomain of each of the clock-controller's listed power-domains. GDSCs with an explicitly defined parent should attach only to the parent GDSC and not the listed power-domains. Any votes will trickle through the hierarchy up to the external power-domains. ======================================== :: arch/arm64/boot/dts/example.dtsi :: ======================================== clockcc: clock-controller@0 { compat ="qcom,example-clockcc"; power-domains = <&pd_a, &pd_b>; } ======================================== :: drivers/clk/qcom/example-clockcc.c :: ======================================== static struct gdsc parent_gdsc = { .pd = { .name = "parent_gdsc", }, }; static struct gdsc child0_gdsc = { .pd = { .name = "child0_gdsc", }, .parent = &parent_gdsc.pd, }; static struct gdsc child1_gdsc = { .pd = { .name = "child1_gdsc", }, .parent = &parent_gdsc.pd, }; ======================================== :: power-subdomains :: ======================================== pm-domain::pd_a └── pm-subdomain::clockcc::parent_gdsc ├── pm-subdomain::clockcc::child0_gdsc └── pm-subdomain::clockcc::child1_gdsc pm-domain::pd_b └── pm-subdomain::clockcc::parent_gdsc ├── pm-subdomain::clockcc::child1_gdsc └── pm-subdomain::clockcc::child2_gdsc The performance states will percolate through the pm-domain hierarchy to the domains that handle the relevant states. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Link: https://lore.kernel.org/r/20250117-b4-linux-next-24-11-18-clock-multiple-power-domains-v10-4-13f2bb656dad@linaro.org Signed-off-by: Bjorn Andersson <andersson@kernel.org>
102 lines
2.8 KiB
C
102 lines
2.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2015, 2017-2018, 2022, The Linux Foundation. All rights reserved.
|
|
*/
|
|
|
|
#ifndef __QCOM_GDSC_H__
|
|
#define __QCOM_GDSC_H__
|
|
|
|
#include <linux/err.h>
|
|
#include <linux/pm_domain.h>
|
|
|
|
struct regmap;
|
|
struct regulator;
|
|
struct reset_controller_dev;
|
|
|
|
/**
|
|
* struct gdsc - Globally Distributed Switch Controller
|
|
* @pd: generic power domain
|
|
* @regmap: regmap for MMIO accesses
|
|
* @gdscr: gsdc control register
|
|
* @collapse_ctrl: APCS collapse-vote register
|
|
* @collapse_mask: APCS collapse-vote mask
|
|
* @gds_hw_ctrl: gds_hw_ctrl register
|
|
* @cxcs: offsets of branch registers to toggle mem/periph bits in
|
|
* @cxc_count: number of @cxcs
|
|
* @pwrsts: Possible powerdomain power states
|
|
* @en_rest_wait_val: transition delay value for receiving enr ack signal
|
|
* @en_few_wait_val: transition delay value for receiving enf ack signal
|
|
* @clk_dis_wait_val: transition delay value for halting clock
|
|
* @resets: ids of resets associated with this gdsc
|
|
* @reset_count: number of @resets
|
|
* @rcdev: reset controller
|
|
*/
|
|
struct gdsc {
|
|
struct generic_pm_domain pd;
|
|
struct generic_pm_domain *parent;
|
|
struct regmap *regmap;
|
|
unsigned int gdscr;
|
|
unsigned int collapse_ctrl;
|
|
unsigned int collapse_mask;
|
|
unsigned int gds_hw_ctrl;
|
|
unsigned int clamp_io_ctrl;
|
|
unsigned int *cxcs;
|
|
unsigned int cxc_count;
|
|
unsigned int en_rest_wait_val;
|
|
unsigned int en_few_wait_val;
|
|
unsigned int clk_dis_wait_val;
|
|
const u8 pwrsts;
|
|
/* Powerdomain allowable state bitfields */
|
|
#define PWRSTS_OFF BIT(0)
|
|
/*
|
|
* There is no SW control to transition a GDSC into
|
|
* PWRSTS_RET. This happens in HW when the parent
|
|
* domain goes down to a low power state
|
|
*/
|
|
#define PWRSTS_RET BIT(1)
|
|
#define PWRSTS_ON BIT(2)
|
|
#define PWRSTS_OFF_ON (PWRSTS_OFF | PWRSTS_ON)
|
|
#define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON)
|
|
const u16 flags;
|
|
#define VOTABLE BIT(0)
|
|
#define CLAMP_IO BIT(1)
|
|
#define HW_CTRL BIT(2)
|
|
#define SW_RESET BIT(3)
|
|
#define AON_RESET BIT(4)
|
|
#define POLL_CFG_GDSCR BIT(5)
|
|
#define ALWAYS_ON BIT(6)
|
|
#define RETAIN_FF_ENABLE BIT(7)
|
|
#define NO_RET_PERIPH BIT(8)
|
|
#define HW_CTRL_TRIGGER BIT(9)
|
|
struct reset_controller_dev *rcdev;
|
|
unsigned int *resets;
|
|
unsigned int reset_count;
|
|
|
|
const char *supply;
|
|
struct regulator *rsupply;
|
|
};
|
|
|
|
struct gdsc_desc {
|
|
struct device *dev;
|
|
struct gdsc **scs;
|
|
size_t num;
|
|
struct dev_pm_domain_list *pd_list;
|
|
};
|
|
|
|
#ifdef CONFIG_QCOM_GDSC
|
|
int gdsc_register(struct gdsc_desc *desc, struct reset_controller_dev *,
|
|
struct regmap *);
|
|
void gdsc_unregister(struct gdsc_desc *desc);
|
|
int gdsc_gx_do_nothing_enable(struct generic_pm_domain *domain);
|
|
#else
|
|
static inline int gdsc_register(struct gdsc_desc *desc,
|
|
struct reset_controller_dev *rcdev,
|
|
struct regmap *r)
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
|
|
static inline void gdsc_unregister(struct gdsc_desc *desc) {};
|
|
#endif /* CONFIG_QCOM_GDSC */
|
|
#endif /* __QCOM_GDSC_H__ */
|