162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Rockchip Generic power domain support.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2015 ROCKCHIP, Co. Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/iopoll.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/mutex.h>
1262306a36Sopenharmony_ci#include <linux/pm_clock.h>
1362306a36Sopenharmony_ci#include <linux/pm_domain.h>
1462306a36Sopenharmony_ci#include <linux/of_address.h>
1562306a36Sopenharmony_ci#include <linux/of_clk.h>
1662306a36Sopenharmony_ci#include <linux/of_platform.h>
1762306a36Sopenharmony_ci#include <linux/clk.h>
1862306a36Sopenharmony_ci#include <linux/regmap.h>
1962306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
2062306a36Sopenharmony_ci#include <soc/rockchip/pm_domains.h>
2162306a36Sopenharmony_ci#include <dt-bindings/power/px30-power.h>
2262306a36Sopenharmony_ci#include <dt-bindings/power/rockchip,rv1126-power.h>
2362306a36Sopenharmony_ci#include <dt-bindings/power/rk3036-power.h>
2462306a36Sopenharmony_ci#include <dt-bindings/power/rk3066-power.h>
2562306a36Sopenharmony_ci#include <dt-bindings/power/rk3128-power.h>
2662306a36Sopenharmony_ci#include <dt-bindings/power/rk3188-power.h>
2762306a36Sopenharmony_ci#include <dt-bindings/power/rk3228-power.h>
2862306a36Sopenharmony_ci#include <dt-bindings/power/rk3288-power.h>
2962306a36Sopenharmony_ci#include <dt-bindings/power/rk3328-power.h>
3062306a36Sopenharmony_ci#include <dt-bindings/power/rk3366-power.h>
3162306a36Sopenharmony_ci#include <dt-bindings/power/rk3368-power.h>
3262306a36Sopenharmony_ci#include <dt-bindings/power/rk3399-power.h>
3362306a36Sopenharmony_ci#include <dt-bindings/power/rk3568-power.h>
3462306a36Sopenharmony_ci#include <dt-bindings/power/rk3588-power.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct rockchip_domain_info {
3762306a36Sopenharmony_ci	const char *name;
3862306a36Sopenharmony_ci	int pwr_mask;
3962306a36Sopenharmony_ci	int status_mask;
4062306a36Sopenharmony_ci	int req_mask;
4162306a36Sopenharmony_ci	int idle_mask;
4262306a36Sopenharmony_ci	int ack_mask;
4362306a36Sopenharmony_ci	bool active_wakeup;
4462306a36Sopenharmony_ci	int pwr_w_mask;
4562306a36Sopenharmony_ci	int req_w_mask;
4662306a36Sopenharmony_ci	int mem_status_mask;
4762306a36Sopenharmony_ci	int repair_status_mask;
4862306a36Sopenharmony_ci	u32 pwr_offset;
4962306a36Sopenharmony_ci	u32 mem_offset;
5062306a36Sopenharmony_ci	u32 req_offset;
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct rockchip_pmu_info {
5462306a36Sopenharmony_ci	u32 pwr_offset;
5562306a36Sopenharmony_ci	u32 status_offset;
5662306a36Sopenharmony_ci	u32 req_offset;
5762306a36Sopenharmony_ci	u32 idle_offset;
5862306a36Sopenharmony_ci	u32 ack_offset;
5962306a36Sopenharmony_ci	u32 mem_pwr_offset;
6062306a36Sopenharmony_ci	u32 chain_status_offset;
6162306a36Sopenharmony_ci	u32 mem_status_offset;
6262306a36Sopenharmony_ci	u32 repair_status_offset;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	u32 core_pwrcnt_offset;
6562306a36Sopenharmony_ci	u32 gpu_pwrcnt_offset;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	unsigned int core_power_transition_time;
6862306a36Sopenharmony_ci	unsigned int gpu_power_transition_time;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	int num_domains;
7162306a36Sopenharmony_ci	const struct rockchip_domain_info *domain_info;
7262306a36Sopenharmony_ci};
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define MAX_QOS_REGS_NUM	5
7562306a36Sopenharmony_ci#define QOS_PRIORITY		0x08
7662306a36Sopenharmony_ci#define QOS_MODE		0x0c
7762306a36Sopenharmony_ci#define QOS_BANDWIDTH		0x10
7862306a36Sopenharmony_ci#define QOS_SATURATION		0x14
7962306a36Sopenharmony_ci#define QOS_EXTCONTROL		0x18
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct rockchip_pm_domain {
8262306a36Sopenharmony_ci	struct generic_pm_domain genpd;
8362306a36Sopenharmony_ci	const struct rockchip_domain_info *info;
8462306a36Sopenharmony_ci	struct rockchip_pmu *pmu;
8562306a36Sopenharmony_ci	int num_qos;
8662306a36Sopenharmony_ci	struct regmap **qos_regmap;
8762306a36Sopenharmony_ci	u32 *qos_save_regs[MAX_QOS_REGS_NUM];
8862306a36Sopenharmony_ci	int num_clks;
8962306a36Sopenharmony_ci	struct clk_bulk_data *clks;
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistruct rockchip_pmu {
9362306a36Sopenharmony_ci	struct device *dev;
9462306a36Sopenharmony_ci	struct regmap *regmap;
9562306a36Sopenharmony_ci	const struct rockchip_pmu_info *info;
9662306a36Sopenharmony_ci	struct mutex mutex; /* mutex lock for pmu */
9762306a36Sopenharmony_ci	struct genpd_onecell_data genpd_data;
9862306a36Sopenharmony_ci	struct generic_pm_domain *domains[];
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define DOMAIN(_name, pwr, status, req, idle, ack, wakeup)	\
10462306a36Sopenharmony_ci{							\
10562306a36Sopenharmony_ci	.name = _name,				\
10662306a36Sopenharmony_ci	.pwr_mask = (pwr),				\
10762306a36Sopenharmony_ci	.status_mask = (status),			\
10862306a36Sopenharmony_ci	.req_mask = (req),				\
10962306a36Sopenharmony_ci	.idle_mask = (idle),				\
11062306a36Sopenharmony_ci	.ack_mask = (ack),				\
11162306a36Sopenharmony_ci	.active_wakeup = (wakeup),			\
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define DOMAIN_M(_name, pwr, status, req, idle, ack, wakeup)	\
11562306a36Sopenharmony_ci{							\
11662306a36Sopenharmony_ci	.name = _name,				\
11762306a36Sopenharmony_ci	.pwr_w_mask = (pwr) << 16,			\
11862306a36Sopenharmony_ci	.pwr_mask = (pwr),				\
11962306a36Sopenharmony_ci	.status_mask = (status),			\
12062306a36Sopenharmony_ci	.req_w_mask = (req) << 16,			\
12162306a36Sopenharmony_ci	.req_mask = (req),				\
12262306a36Sopenharmony_ci	.idle_mask = (idle),				\
12362306a36Sopenharmony_ci	.ack_mask = (ack),				\
12462306a36Sopenharmony_ci	.active_wakeup = wakeup,			\
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup)	\
12862306a36Sopenharmony_ci{							\
12962306a36Sopenharmony_ci	.name = _name,					\
13062306a36Sopenharmony_ci	.pwr_offset = p_offset,				\
13162306a36Sopenharmony_ci	.pwr_w_mask = (pwr) << 16,			\
13262306a36Sopenharmony_ci	.pwr_mask = (pwr),				\
13362306a36Sopenharmony_ci	.status_mask = (status),			\
13462306a36Sopenharmony_ci	.mem_offset = m_offset,				\
13562306a36Sopenharmony_ci	.mem_status_mask = (m_status),			\
13662306a36Sopenharmony_ci	.repair_status_mask = (r_status),		\
13762306a36Sopenharmony_ci	.req_offset = r_offset,				\
13862306a36Sopenharmony_ci	.req_w_mask = (req) << 16,			\
13962306a36Sopenharmony_ci	.req_mask = (req),				\
14062306a36Sopenharmony_ci	.idle_mask = (idle),				\
14162306a36Sopenharmony_ci	.ack_mask = (ack),				\
14262306a36Sopenharmony_ci	.active_wakeup = wakeup,			\
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define DOMAIN_RK3036(_name, req, ack, idle, wakeup)		\
14662306a36Sopenharmony_ci{							\
14762306a36Sopenharmony_ci	.name = _name,				\
14862306a36Sopenharmony_ci	.req_mask = (req),				\
14962306a36Sopenharmony_ci	.req_w_mask = (req) << 16,			\
15062306a36Sopenharmony_ci	.ack_mask = (ack),				\
15162306a36Sopenharmony_ci	.idle_mask = (idle),				\
15262306a36Sopenharmony_ci	.active_wakeup = wakeup,			\
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci#define DOMAIN_PX30(name, pwr, status, req, wakeup)		\
15662306a36Sopenharmony_ci	DOMAIN_M(name, pwr, status, req, (req) << 16, req, wakeup)
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci#define DOMAIN_RV1126(name, pwr, req, idle, wakeup)		\
15962306a36Sopenharmony_ci	DOMAIN_M(name, pwr, pwr, req, idle, idle, wakeup)
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci#define DOMAIN_RK3288(name, pwr, status, req, wakeup)		\
16262306a36Sopenharmony_ci	DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup)
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define DOMAIN_RK3328(name, pwr, status, req, wakeup)		\
16562306a36Sopenharmony_ci	DOMAIN_M(name, pwr, pwr, req, (req) << 10, req, wakeup)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#define DOMAIN_RK3368(name, pwr, status, req, wakeup)		\
16862306a36Sopenharmony_ci	DOMAIN(name, pwr, status, req, (req) << 16, req, wakeup)
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#define DOMAIN_RK3399(name, pwr, status, req, wakeup)		\
17162306a36Sopenharmony_ci	DOMAIN(name, pwr, status, req, req, req, wakeup)
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define DOMAIN_RK3568(name, pwr, req, wakeup)		\
17462306a36Sopenharmony_ci	DOMAIN_M(name, pwr, pwr, req, req, req, wakeup)
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/*
17762306a36Sopenharmony_ci * Dynamic Memory Controller may need to coordinate with us -- see
17862306a36Sopenharmony_ci * rockchip_pmu_block().
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci * dmc_pmu_mutex protects registration-time races, so DMC driver doesn't try to
18162306a36Sopenharmony_ci * block() while we're initializing the PMU.
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_cistatic DEFINE_MUTEX(dmc_pmu_mutex);
18462306a36Sopenharmony_cistatic struct rockchip_pmu *dmc_pmu;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/*
18762306a36Sopenharmony_ci * Block PMU transitions and make sure they don't interfere with ARM Trusted
18862306a36Sopenharmony_ci * Firmware operations. There are two conflicts, noted in the comments below.
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci * Caller must unblock PMU transitions via rockchip_pmu_unblock().
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_ciint rockchip_pmu_block(void)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct rockchip_pmu *pmu;
19562306a36Sopenharmony_ci	struct generic_pm_domain *genpd;
19662306a36Sopenharmony_ci	struct rockchip_pm_domain *pd;
19762306a36Sopenharmony_ci	int i, ret;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	mutex_lock(&dmc_pmu_mutex);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* No PMU (yet)? Then we just block rockchip_pmu_probe(). */
20262306a36Sopenharmony_ci	if (!dmc_pmu)
20362306a36Sopenharmony_ci		return 0;
20462306a36Sopenharmony_ci	pmu = dmc_pmu;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/*
20762306a36Sopenharmony_ci	 * mutex blocks all idle transitions: we can't touch the
20862306a36Sopenharmony_ci	 * PMU_BUS_IDLE_REQ (our ".idle_offset") register while ARM Trusted
20962306a36Sopenharmony_ci	 * Firmware might be using it.
21062306a36Sopenharmony_ci	 */
21162306a36Sopenharmony_ci	mutex_lock(&pmu->mutex);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/*
21462306a36Sopenharmony_ci	 * Power domain clocks: Per Rockchip, we *must* keep certain clocks
21562306a36Sopenharmony_ci	 * enabled for the duration of power-domain transitions. Most
21662306a36Sopenharmony_ci	 * transitions are handled by this driver, but some cases (in
21762306a36Sopenharmony_ci	 * particular, DRAM DVFS / memory-controller idle) must be handled by
21862306a36Sopenharmony_ci	 * firmware. Firmware can handle most clock management via a special
21962306a36Sopenharmony_ci	 * "ungate" register (PMU_CRU_GATEDIS_CON0), but unfortunately, this
22062306a36Sopenharmony_ci	 * doesn't handle PLLs. We can assist this transition by doing the
22162306a36Sopenharmony_ci	 * clock management on behalf of firmware.
22262306a36Sopenharmony_ci	 */
22362306a36Sopenharmony_ci	for (i = 0; i < pmu->genpd_data.num_domains; i++) {
22462306a36Sopenharmony_ci		genpd = pmu->genpd_data.domains[i];
22562306a36Sopenharmony_ci		if (genpd) {
22662306a36Sopenharmony_ci			pd = to_rockchip_pd(genpd);
22762306a36Sopenharmony_ci			ret = clk_bulk_enable(pd->num_clks, pd->clks);
22862306a36Sopenharmony_ci			if (ret < 0) {
22962306a36Sopenharmony_ci				dev_err(pmu->dev,
23062306a36Sopenharmony_ci					"failed to enable clks for domain '%s': %d\n",
23162306a36Sopenharmony_ci					genpd->name, ret);
23262306a36Sopenharmony_ci				goto err;
23362306a36Sopenharmony_ci			}
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return 0;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cierr:
24062306a36Sopenharmony_ci	for (i = i - 1; i >= 0; i--) {
24162306a36Sopenharmony_ci		genpd = pmu->genpd_data.domains[i];
24262306a36Sopenharmony_ci		if (genpd) {
24362306a36Sopenharmony_ci			pd = to_rockchip_pd(genpd);
24462306a36Sopenharmony_ci			clk_bulk_disable(pd->num_clks, pd->clks);
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci	mutex_unlock(&pmu->mutex);
24862306a36Sopenharmony_ci	mutex_unlock(&dmc_pmu_mutex);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	return ret;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pmu_block);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/* Unblock PMU transitions. */
25562306a36Sopenharmony_civoid rockchip_pmu_unblock(void)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct rockchip_pmu *pmu;
25862306a36Sopenharmony_ci	struct generic_pm_domain *genpd;
25962306a36Sopenharmony_ci	struct rockchip_pm_domain *pd;
26062306a36Sopenharmony_ci	int i;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (dmc_pmu) {
26362306a36Sopenharmony_ci		pmu = dmc_pmu;
26462306a36Sopenharmony_ci		for (i = 0; i < pmu->genpd_data.num_domains; i++) {
26562306a36Sopenharmony_ci			genpd = pmu->genpd_data.domains[i];
26662306a36Sopenharmony_ci			if (genpd) {
26762306a36Sopenharmony_ci				pd = to_rockchip_pd(genpd);
26862306a36Sopenharmony_ci				clk_bulk_disable(pd->num_clks, pd->clks);
26962306a36Sopenharmony_ci			}
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		mutex_unlock(&pmu->mutex);
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	mutex_unlock(&dmc_pmu_mutex);
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pmu_unblock);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci#define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup)	\
28062306a36Sopenharmony_ci	DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup)
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
28562306a36Sopenharmony_ci	const struct rockchip_domain_info *pd_info = pd->info;
28662306a36Sopenharmony_ci	unsigned int val;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	regmap_read(pmu->regmap, pmu->info->idle_offset, &val);
28962306a36Sopenharmony_ci	return (val & pd_info->idle_mask) == pd_info->idle_mask;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	unsigned int val;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
29762306a36Sopenharmony_ci	return val;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
30162306a36Sopenharmony_ci					 bool idle)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	const struct rockchip_domain_info *pd_info = pd->info;
30462306a36Sopenharmony_ci	struct generic_pm_domain *genpd = &pd->genpd;
30562306a36Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
30662306a36Sopenharmony_ci	u32 pd_req_offset = pd_info->req_offset;
30762306a36Sopenharmony_ci	unsigned int target_ack;
30862306a36Sopenharmony_ci	unsigned int val;
30962306a36Sopenharmony_ci	bool is_idle;
31062306a36Sopenharmony_ci	int ret;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (pd_info->req_mask == 0)
31362306a36Sopenharmony_ci		return 0;
31462306a36Sopenharmony_ci	else if (pd_info->req_w_mask)
31562306a36Sopenharmony_ci		regmap_write(pmu->regmap, pmu->info->req_offset + pd_req_offset,
31662306a36Sopenharmony_ci			     idle ? (pd_info->req_mask | pd_info->req_w_mask) :
31762306a36Sopenharmony_ci			     pd_info->req_w_mask);
31862306a36Sopenharmony_ci	else
31962306a36Sopenharmony_ci		regmap_update_bits(pmu->regmap, pmu->info->req_offset + pd_req_offset,
32062306a36Sopenharmony_ci				   pd_info->req_mask, idle ? -1U : 0);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	wmb();
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Wait util idle_ack = 1 */
32562306a36Sopenharmony_ci	target_ack = idle ? pd_info->ack_mask : 0;
32662306a36Sopenharmony_ci	ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val,
32762306a36Sopenharmony_ci					(val & pd_info->ack_mask) == target_ack,
32862306a36Sopenharmony_ci					0, 10000);
32962306a36Sopenharmony_ci	if (ret) {
33062306a36Sopenharmony_ci		dev_err(pmu->dev,
33162306a36Sopenharmony_ci			"failed to get ack on domain '%s', val=0x%x\n",
33262306a36Sopenharmony_ci			genpd->name, val);
33362306a36Sopenharmony_ci		return ret;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd,
33762306a36Sopenharmony_ci					is_idle, is_idle == idle, 0, 10000);
33862306a36Sopenharmony_ci	if (ret) {
33962306a36Sopenharmony_ci		dev_err(pmu->dev,
34062306a36Sopenharmony_ci			"failed to set idle on domain '%s', val=%d\n",
34162306a36Sopenharmony_ci			genpd->name, is_idle);
34262306a36Sopenharmony_ci		return ret;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return 0;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	int i;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	for (i = 0; i < pd->num_qos; i++) {
35362306a36Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
35462306a36Sopenharmony_ci			    QOS_PRIORITY,
35562306a36Sopenharmony_ci			    &pd->qos_save_regs[0][i]);
35662306a36Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
35762306a36Sopenharmony_ci			    QOS_MODE,
35862306a36Sopenharmony_ci			    &pd->qos_save_regs[1][i]);
35962306a36Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
36062306a36Sopenharmony_ci			    QOS_BANDWIDTH,
36162306a36Sopenharmony_ci			    &pd->qos_save_regs[2][i]);
36262306a36Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
36362306a36Sopenharmony_ci			    QOS_SATURATION,
36462306a36Sopenharmony_ci			    &pd->qos_save_regs[3][i]);
36562306a36Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
36662306a36Sopenharmony_ci			    QOS_EXTCONTROL,
36762306a36Sopenharmony_ci			    &pd->qos_save_regs[4][i]);
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci	return 0;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	int i;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	for (i = 0; i < pd->num_qos; i++) {
37762306a36Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
37862306a36Sopenharmony_ci			     QOS_PRIORITY,
37962306a36Sopenharmony_ci			     pd->qos_save_regs[0][i]);
38062306a36Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
38162306a36Sopenharmony_ci			     QOS_MODE,
38262306a36Sopenharmony_ci			     pd->qos_save_regs[1][i]);
38362306a36Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
38462306a36Sopenharmony_ci			     QOS_BANDWIDTH,
38562306a36Sopenharmony_ci			     pd->qos_save_regs[2][i]);
38662306a36Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
38762306a36Sopenharmony_ci			     QOS_SATURATION,
38862306a36Sopenharmony_ci			     pd->qos_save_regs[3][i]);
38962306a36Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
39062306a36Sopenharmony_ci			     QOS_EXTCONTROL,
39162306a36Sopenharmony_ci			     pd->qos_save_regs[4][i]);
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return 0;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
40062306a36Sopenharmony_ci	unsigned int val;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (pd->info->repair_status_mask) {
40362306a36Sopenharmony_ci		regmap_read(pmu->regmap, pmu->info->repair_status_offset, &val);
40462306a36Sopenharmony_ci		/* 1'b1: power on, 1'b0: power off */
40562306a36Sopenharmony_ci		return val & pd->info->repair_status_mask;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* check idle status for idle-only domains */
40962306a36Sopenharmony_ci	if (pd->info->status_mask == 0)
41062306a36Sopenharmony_ci		return !rockchip_pmu_domain_is_idle(pd);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	regmap_read(pmu->regmap, pmu->info->status_offset, &val);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* 1'b0: power on, 1'b1: power off */
41562306a36Sopenharmony_ci	return !(val & pd->info->status_mask);
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic bool rockchip_pmu_domain_is_mem_on(struct rockchip_pm_domain *pd)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
42162306a36Sopenharmony_ci	unsigned int val;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	regmap_read(pmu->regmap,
42462306a36Sopenharmony_ci		    pmu->info->mem_status_offset + pd->info->mem_offset, &val);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* 1'b0: power on, 1'b1: power off */
42762306a36Sopenharmony_ci	return !(val & pd->info->mem_status_mask);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic bool rockchip_pmu_domain_is_chain_on(struct rockchip_pm_domain *pd)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
43362306a36Sopenharmony_ci	unsigned int val;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	regmap_read(pmu->regmap,
43662306a36Sopenharmony_ci		    pmu->info->chain_status_offset + pd->info->mem_offset, &val);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* 1'b1: power on, 1'b0: power off */
43962306a36Sopenharmony_ci	return val & pd->info->mem_status_mask;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic int rockchip_pmu_domain_mem_reset(struct rockchip_pm_domain *pd)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
44562306a36Sopenharmony_ci	struct generic_pm_domain *genpd = &pd->genpd;
44662306a36Sopenharmony_ci	bool is_on;
44762306a36Sopenharmony_ci	int ret = 0;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_chain_on, pd, is_on,
45062306a36Sopenharmony_ci					is_on == true, 0, 10000);
45162306a36Sopenharmony_ci	if (ret) {
45262306a36Sopenharmony_ci		dev_err(pmu->dev,
45362306a36Sopenharmony_ci			"failed to get chain status '%s', target_on=1, val=%d\n",
45462306a36Sopenharmony_ci			genpd->name, is_on);
45562306a36Sopenharmony_ci		goto error;
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	udelay(20);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	regmap_write(pmu->regmap, pmu->info->mem_pwr_offset + pd->info->pwr_offset,
46162306a36Sopenharmony_ci		     (pd->info->pwr_mask | pd->info->pwr_w_mask));
46262306a36Sopenharmony_ci	wmb();
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_mem_on, pd, is_on,
46562306a36Sopenharmony_ci					is_on == false, 0, 10000);
46662306a36Sopenharmony_ci	if (ret) {
46762306a36Sopenharmony_ci		dev_err(pmu->dev,
46862306a36Sopenharmony_ci			"failed to get mem status '%s', target_on=0, val=%d\n",
46962306a36Sopenharmony_ci			genpd->name, is_on);
47062306a36Sopenharmony_ci		goto error;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	regmap_write(pmu->regmap, pmu->info->mem_pwr_offset + pd->info->pwr_offset,
47462306a36Sopenharmony_ci		     pd->info->pwr_w_mask);
47562306a36Sopenharmony_ci	wmb();
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_mem_on, pd, is_on,
47862306a36Sopenharmony_ci					is_on == true, 0, 10000);
47962306a36Sopenharmony_ci	if (ret) {
48062306a36Sopenharmony_ci		dev_err(pmu->dev,
48162306a36Sopenharmony_ci			"failed to get mem status '%s', target_on=1, val=%d\n",
48262306a36Sopenharmony_ci			genpd->name, is_on);
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cierror:
48662306a36Sopenharmony_ci	return ret;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
49062306a36Sopenharmony_ci					     bool on)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
49362306a36Sopenharmony_ci	struct generic_pm_domain *genpd = &pd->genpd;
49462306a36Sopenharmony_ci	u32 pd_pwr_offset = pd->info->pwr_offset;
49562306a36Sopenharmony_ci	bool is_on, is_mem_on = false;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (pd->info->pwr_mask == 0)
49862306a36Sopenharmony_ci		return;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (on && pd->info->mem_status_mask)
50162306a36Sopenharmony_ci		is_mem_on = rockchip_pmu_domain_is_mem_on(pd);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (pd->info->pwr_w_mask)
50462306a36Sopenharmony_ci		regmap_write(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset,
50562306a36Sopenharmony_ci			     on ? pd->info->pwr_w_mask :
50662306a36Sopenharmony_ci			     (pd->info->pwr_mask | pd->info->pwr_w_mask));
50762306a36Sopenharmony_ci	else
50862306a36Sopenharmony_ci		regmap_update_bits(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset,
50962306a36Sopenharmony_ci				   pd->info->pwr_mask, on ? 0 : -1U);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	wmb();
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (is_mem_on && rockchip_pmu_domain_mem_reset(pd))
51462306a36Sopenharmony_ci		return;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
51762306a36Sopenharmony_ci				      is_on == on, 0, 10000)) {
51862306a36Sopenharmony_ci		dev_err(pmu->dev,
51962306a36Sopenharmony_ci			"failed to set domain '%s', val=%d\n",
52062306a36Sopenharmony_ci			genpd->name, is_on);
52162306a36Sopenharmony_ci		return;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
52862306a36Sopenharmony_ci	int ret;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	mutex_lock(&pmu->mutex);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (rockchip_pmu_domain_is_on(pd) != power_on) {
53362306a36Sopenharmony_ci		ret = clk_bulk_enable(pd->num_clks, pd->clks);
53462306a36Sopenharmony_ci		if (ret < 0) {
53562306a36Sopenharmony_ci			dev_err(pmu->dev, "failed to enable clocks\n");
53662306a36Sopenharmony_ci			mutex_unlock(&pmu->mutex);
53762306a36Sopenharmony_ci			return ret;
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		if (!power_on) {
54162306a36Sopenharmony_ci			rockchip_pmu_save_qos(pd);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci			/* if powering down, idle request to NIU first */
54462306a36Sopenharmony_ci			rockchip_pmu_set_idle_request(pd, true);
54562306a36Sopenharmony_ci		}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		rockchip_do_pmu_set_power_domain(pd, power_on);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		if (power_on) {
55062306a36Sopenharmony_ci			/* if powering up, leave idle mode */
55162306a36Sopenharmony_ci			rockchip_pmu_set_idle_request(pd, false);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci			rockchip_pmu_restore_qos(pd);
55462306a36Sopenharmony_ci		}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		clk_bulk_disable(pd->num_clks, pd->clks);
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	mutex_unlock(&pmu->mutex);
56062306a36Sopenharmony_ci	return 0;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic int rockchip_pd_power_on(struct generic_pm_domain *domain)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return rockchip_pd_power(pd, true);
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic int rockchip_pd_power_off(struct generic_pm_domain *domain)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	return rockchip_pd_power(pd, false);
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
57862306a36Sopenharmony_ci				  struct device *dev)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct clk *clk;
58162306a36Sopenharmony_ci	int i;
58262306a36Sopenharmony_ci	int error;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	error = pm_clk_create(dev);
58762306a36Sopenharmony_ci	if (error) {
58862306a36Sopenharmony_ci		dev_err(dev, "pm_clk_create failed %d\n", error);
58962306a36Sopenharmony_ci		return error;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	i = 0;
59362306a36Sopenharmony_ci	while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
59462306a36Sopenharmony_ci		dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
59562306a36Sopenharmony_ci		error = pm_clk_add_clk(dev, clk);
59662306a36Sopenharmony_ci		if (error) {
59762306a36Sopenharmony_ci			dev_err(dev, "pm_clk_add_clk failed %d\n", error);
59862306a36Sopenharmony_ci			clk_put(clk);
59962306a36Sopenharmony_ci			pm_clk_destroy(dev);
60062306a36Sopenharmony_ci			return error;
60162306a36Sopenharmony_ci		}
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
60862306a36Sopenharmony_ci				   struct device *dev)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	pm_clk_destroy(dev);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
61662306a36Sopenharmony_ci				      struct device_node *node)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	const struct rockchip_domain_info *pd_info;
61962306a36Sopenharmony_ci	struct rockchip_pm_domain *pd;
62062306a36Sopenharmony_ci	struct device_node *qos_node;
62162306a36Sopenharmony_ci	int i, j;
62262306a36Sopenharmony_ci	u32 id;
62362306a36Sopenharmony_ci	int error;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	error = of_property_read_u32(node, "reg", &id);
62662306a36Sopenharmony_ci	if (error) {
62762306a36Sopenharmony_ci		dev_err(pmu->dev,
62862306a36Sopenharmony_ci			"%pOFn: failed to retrieve domain id (reg): %d\n",
62962306a36Sopenharmony_ci			node, error);
63062306a36Sopenharmony_ci		return -EINVAL;
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	if (id >= pmu->info->num_domains) {
63462306a36Sopenharmony_ci		dev_err(pmu->dev, "%pOFn: invalid domain id %d\n",
63562306a36Sopenharmony_ci			node, id);
63662306a36Sopenharmony_ci		return -EINVAL;
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci	/* RK3588 has domains with two parents (RKVDEC0/RKVDEC1) */
63962306a36Sopenharmony_ci	if (pmu->genpd_data.domains[id])
64062306a36Sopenharmony_ci		return 0;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	pd_info = &pmu->info->domain_info[id];
64362306a36Sopenharmony_ci	if (!pd_info) {
64462306a36Sopenharmony_ci		dev_err(pmu->dev, "%pOFn: undefined domain id %d\n",
64562306a36Sopenharmony_ci			node, id);
64662306a36Sopenharmony_ci		return -EINVAL;
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
65062306a36Sopenharmony_ci	if (!pd)
65162306a36Sopenharmony_ci		return -ENOMEM;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	pd->info = pd_info;
65462306a36Sopenharmony_ci	pd->pmu = pmu;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	pd->num_clks = of_clk_get_parent_count(node);
65762306a36Sopenharmony_ci	if (pd->num_clks > 0) {
65862306a36Sopenharmony_ci		pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,
65962306a36Sopenharmony_ci					sizeof(*pd->clks), GFP_KERNEL);
66062306a36Sopenharmony_ci		if (!pd->clks)
66162306a36Sopenharmony_ci			return -ENOMEM;
66262306a36Sopenharmony_ci	} else {
66362306a36Sopenharmony_ci		dev_dbg(pmu->dev, "%pOFn: doesn't have clocks: %d\n",
66462306a36Sopenharmony_ci			node, pd->num_clks);
66562306a36Sopenharmony_ci		pd->num_clks = 0;
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	for (i = 0; i < pd->num_clks; i++) {
66962306a36Sopenharmony_ci		pd->clks[i].clk = of_clk_get(node, i);
67062306a36Sopenharmony_ci		if (IS_ERR(pd->clks[i].clk)) {
67162306a36Sopenharmony_ci			error = PTR_ERR(pd->clks[i].clk);
67262306a36Sopenharmony_ci			dev_err(pmu->dev,
67362306a36Sopenharmony_ci				"%pOFn: failed to get clk at index %d: %d\n",
67462306a36Sopenharmony_ci				node, i, error);
67562306a36Sopenharmony_ci			return error;
67662306a36Sopenharmony_ci		}
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	error = clk_bulk_prepare(pd->num_clks, pd->clks);
68062306a36Sopenharmony_ci	if (error)
68162306a36Sopenharmony_ci		goto err_put_clocks;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
68462306a36Sopenharmony_ci						 NULL);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	if (pd->num_qos > 0) {
68762306a36Sopenharmony_ci		pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,
68862306a36Sopenharmony_ci					      sizeof(*pd->qos_regmap),
68962306a36Sopenharmony_ci					      GFP_KERNEL);
69062306a36Sopenharmony_ci		if (!pd->qos_regmap) {
69162306a36Sopenharmony_ci			error = -ENOMEM;
69262306a36Sopenharmony_ci			goto err_unprepare_clocks;
69362306a36Sopenharmony_ci		}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
69662306a36Sopenharmony_ci			pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,
69762306a36Sopenharmony_ci							    pd->num_qos,
69862306a36Sopenharmony_ci							    sizeof(u32),
69962306a36Sopenharmony_ci							    GFP_KERNEL);
70062306a36Sopenharmony_ci			if (!pd->qos_save_regs[j]) {
70162306a36Sopenharmony_ci				error = -ENOMEM;
70262306a36Sopenharmony_ci				goto err_unprepare_clocks;
70362306a36Sopenharmony_ci			}
70462306a36Sopenharmony_ci		}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci		for (j = 0; j < pd->num_qos; j++) {
70762306a36Sopenharmony_ci			qos_node = of_parse_phandle(node, "pm_qos", j);
70862306a36Sopenharmony_ci			if (!qos_node) {
70962306a36Sopenharmony_ci				error = -ENODEV;
71062306a36Sopenharmony_ci				goto err_unprepare_clocks;
71162306a36Sopenharmony_ci			}
71262306a36Sopenharmony_ci			pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
71362306a36Sopenharmony_ci			if (IS_ERR(pd->qos_regmap[j])) {
71462306a36Sopenharmony_ci				error = -ENODEV;
71562306a36Sopenharmony_ci				of_node_put(qos_node);
71662306a36Sopenharmony_ci				goto err_unprepare_clocks;
71762306a36Sopenharmony_ci			}
71862306a36Sopenharmony_ci			of_node_put(qos_node);
71962306a36Sopenharmony_ci		}
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	if (pd->info->name)
72362306a36Sopenharmony_ci		pd->genpd.name = pd->info->name;
72462306a36Sopenharmony_ci	else
72562306a36Sopenharmony_ci		pd->genpd.name = kbasename(node->full_name);
72662306a36Sopenharmony_ci	pd->genpd.power_off = rockchip_pd_power_off;
72762306a36Sopenharmony_ci	pd->genpd.power_on = rockchip_pd_power_on;
72862306a36Sopenharmony_ci	pd->genpd.attach_dev = rockchip_pd_attach_dev;
72962306a36Sopenharmony_ci	pd->genpd.detach_dev = rockchip_pd_detach_dev;
73062306a36Sopenharmony_ci	pd->genpd.flags = GENPD_FLAG_PM_CLK;
73162306a36Sopenharmony_ci	if (pd_info->active_wakeup)
73262306a36Sopenharmony_ci		pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
73362306a36Sopenharmony_ci	pm_genpd_init(&pd->genpd, NULL,
73462306a36Sopenharmony_ci		      !rockchip_pmu_domain_is_on(pd) ||
73562306a36Sopenharmony_ci		      (pd->info->mem_status_mask && !rockchip_pmu_domain_is_mem_on(pd)));
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	pmu->genpd_data.domains[id] = &pd->genpd;
73862306a36Sopenharmony_ci	return 0;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cierr_unprepare_clocks:
74162306a36Sopenharmony_ci	clk_bulk_unprepare(pd->num_clks, pd->clks);
74262306a36Sopenharmony_cierr_put_clocks:
74362306a36Sopenharmony_ci	clk_bulk_put(pd->num_clks, pd->clks);
74462306a36Sopenharmony_ci	return error;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	int ret;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	/*
75262306a36Sopenharmony_ci	 * We're in the error cleanup already, so we only complain,
75362306a36Sopenharmony_ci	 * but won't emit another error on top of the original one.
75462306a36Sopenharmony_ci	 */
75562306a36Sopenharmony_ci	ret = pm_genpd_remove(&pd->genpd);
75662306a36Sopenharmony_ci	if (ret < 0)
75762306a36Sopenharmony_ci		dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",
75862306a36Sopenharmony_ci			pd->genpd.name, ret);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	clk_bulk_unprepare(pd->num_clks, pd->clks);
76162306a36Sopenharmony_ci	clk_bulk_put(pd->num_clks, pd->clks);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	/* protect the zeroing of pm->num_clks */
76462306a36Sopenharmony_ci	mutex_lock(&pd->pmu->mutex);
76562306a36Sopenharmony_ci	pd->num_clks = 0;
76662306a36Sopenharmony_ci	mutex_unlock(&pd->pmu->mutex);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	/* devm will free our memory */
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	struct generic_pm_domain *genpd;
77462306a36Sopenharmony_ci	struct rockchip_pm_domain *pd;
77562306a36Sopenharmony_ci	int i;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	for (i = 0; i < pmu->genpd_data.num_domains; i++) {
77862306a36Sopenharmony_ci		genpd = pmu->genpd_data.domains[i];
77962306a36Sopenharmony_ci		if (genpd) {
78062306a36Sopenharmony_ci			pd = to_rockchip_pd(genpd);
78162306a36Sopenharmony_ci			rockchip_pm_remove_one_domain(pd);
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	/* devm will free our memory */
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
78962306a36Sopenharmony_ci				      u32 domain_reg_offset,
79062306a36Sopenharmony_ci				      unsigned int count)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	/* First configure domain power down transition count ... */
79362306a36Sopenharmony_ci	regmap_write(pmu->regmap, domain_reg_offset, count);
79462306a36Sopenharmony_ci	/* ... and then power up count. */
79562306a36Sopenharmony_ci	regmap_write(pmu->regmap, domain_reg_offset + 4, count);
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
79962306a36Sopenharmony_ci				     struct device_node *parent)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	struct device_node *np;
80262306a36Sopenharmony_ci	struct generic_pm_domain *child_domain, *parent_domain;
80362306a36Sopenharmony_ci	int error;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	for_each_child_of_node(parent, np) {
80662306a36Sopenharmony_ci		u32 idx;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci		error = of_property_read_u32(parent, "reg", &idx);
80962306a36Sopenharmony_ci		if (error) {
81062306a36Sopenharmony_ci			dev_err(pmu->dev,
81162306a36Sopenharmony_ci				"%pOFn: failed to retrieve domain id (reg): %d\n",
81262306a36Sopenharmony_ci				parent, error);
81362306a36Sopenharmony_ci			goto err_out;
81462306a36Sopenharmony_ci		}
81562306a36Sopenharmony_ci		parent_domain = pmu->genpd_data.domains[idx];
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci		error = rockchip_pm_add_one_domain(pmu, np);
81862306a36Sopenharmony_ci		if (error) {
81962306a36Sopenharmony_ci			dev_err(pmu->dev, "failed to handle node %pOFn: %d\n",
82062306a36Sopenharmony_ci				np, error);
82162306a36Sopenharmony_ci			goto err_out;
82262306a36Sopenharmony_ci		}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		error = of_property_read_u32(np, "reg", &idx);
82562306a36Sopenharmony_ci		if (error) {
82662306a36Sopenharmony_ci			dev_err(pmu->dev,
82762306a36Sopenharmony_ci				"%pOFn: failed to retrieve domain id (reg): %d\n",
82862306a36Sopenharmony_ci				np, error);
82962306a36Sopenharmony_ci			goto err_out;
83062306a36Sopenharmony_ci		}
83162306a36Sopenharmony_ci		child_domain = pmu->genpd_data.domains[idx];
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		error = pm_genpd_add_subdomain(parent_domain, child_domain);
83462306a36Sopenharmony_ci		if (error) {
83562306a36Sopenharmony_ci			dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n",
83662306a36Sopenharmony_ci				parent_domain->name, child_domain->name, error);
83762306a36Sopenharmony_ci			goto err_out;
83862306a36Sopenharmony_ci		} else {
83962306a36Sopenharmony_ci			dev_dbg(pmu->dev, "%s add subdomain: %s\n",
84062306a36Sopenharmony_ci				parent_domain->name, child_domain->name);
84162306a36Sopenharmony_ci		}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		rockchip_pm_add_subdomain(pmu, np);
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	return 0;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cierr_out:
84962306a36Sopenharmony_ci	of_node_put(np);
85062306a36Sopenharmony_ci	return error;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic int rockchip_pm_domain_probe(struct platform_device *pdev)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
85662306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
85762306a36Sopenharmony_ci	struct device_node *node;
85862306a36Sopenharmony_ci	struct device *parent;
85962306a36Sopenharmony_ci	struct rockchip_pmu *pmu;
86062306a36Sopenharmony_ci	const struct of_device_id *match;
86162306a36Sopenharmony_ci	const struct rockchip_pmu_info *pmu_info;
86262306a36Sopenharmony_ci	int error;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (!np) {
86562306a36Sopenharmony_ci		dev_err(dev, "device tree node not found\n");
86662306a36Sopenharmony_ci		return -ENODEV;
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	match = of_match_device(dev->driver->of_match_table, dev);
87062306a36Sopenharmony_ci	if (!match || !match->data) {
87162306a36Sopenharmony_ci		dev_err(dev, "missing pmu data\n");
87262306a36Sopenharmony_ci		return -EINVAL;
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	pmu_info = match->data;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	pmu = devm_kzalloc(dev,
87862306a36Sopenharmony_ci			   struct_size(pmu, domains, pmu_info->num_domains),
87962306a36Sopenharmony_ci			   GFP_KERNEL);
88062306a36Sopenharmony_ci	if (!pmu)
88162306a36Sopenharmony_ci		return -ENOMEM;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	pmu->dev = &pdev->dev;
88462306a36Sopenharmony_ci	mutex_init(&pmu->mutex);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	pmu->info = pmu_info;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	pmu->genpd_data.domains = pmu->domains;
88962306a36Sopenharmony_ci	pmu->genpd_data.num_domains = pmu_info->num_domains;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	parent = dev->parent;
89262306a36Sopenharmony_ci	if (!parent) {
89362306a36Sopenharmony_ci		dev_err(dev, "no parent for syscon devices\n");
89462306a36Sopenharmony_ci		return -ENODEV;
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	pmu->regmap = syscon_node_to_regmap(parent->of_node);
89862306a36Sopenharmony_ci	if (IS_ERR(pmu->regmap)) {
89962306a36Sopenharmony_ci		dev_err(dev, "no regmap available\n");
90062306a36Sopenharmony_ci		return PTR_ERR(pmu->regmap);
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	/*
90462306a36Sopenharmony_ci	 * Configure power up and down transition delays for CORE
90562306a36Sopenharmony_ci	 * and GPU domains.
90662306a36Sopenharmony_ci	 */
90762306a36Sopenharmony_ci	if (pmu_info->core_power_transition_time)
90862306a36Sopenharmony_ci		rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
90962306a36Sopenharmony_ci					pmu_info->core_power_transition_time);
91062306a36Sopenharmony_ci	if (pmu_info->gpu_pwrcnt_offset)
91162306a36Sopenharmony_ci		rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
91262306a36Sopenharmony_ci					pmu_info->gpu_power_transition_time);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	error = -ENODEV;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/*
91762306a36Sopenharmony_ci	 * Prevent any rockchip_pmu_block() from racing with the remainder of
91862306a36Sopenharmony_ci	 * setup (clocks, register initialization).
91962306a36Sopenharmony_ci	 */
92062306a36Sopenharmony_ci	mutex_lock(&dmc_pmu_mutex);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	for_each_available_child_of_node(np, node) {
92362306a36Sopenharmony_ci		error = rockchip_pm_add_one_domain(pmu, node);
92462306a36Sopenharmony_ci		if (error) {
92562306a36Sopenharmony_ci			dev_err(dev, "failed to handle node %pOFn: %d\n",
92662306a36Sopenharmony_ci				node, error);
92762306a36Sopenharmony_ci			of_node_put(node);
92862306a36Sopenharmony_ci			goto err_out;
92962306a36Sopenharmony_ci		}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci		error = rockchip_pm_add_subdomain(pmu, node);
93262306a36Sopenharmony_ci		if (error < 0) {
93362306a36Sopenharmony_ci			dev_err(dev, "failed to handle subdomain node %pOFn: %d\n",
93462306a36Sopenharmony_ci				node, error);
93562306a36Sopenharmony_ci			of_node_put(node);
93662306a36Sopenharmony_ci			goto err_out;
93762306a36Sopenharmony_ci		}
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	if (error) {
94162306a36Sopenharmony_ci		dev_dbg(dev, "no power domains defined\n");
94262306a36Sopenharmony_ci		goto err_out;
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	error = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
94662306a36Sopenharmony_ci	if (error) {
94762306a36Sopenharmony_ci		dev_err(dev, "failed to add provider: %d\n", error);
94862306a36Sopenharmony_ci		goto err_out;
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	/* We only expect one PMU. */
95262306a36Sopenharmony_ci	if (!WARN_ON_ONCE(dmc_pmu))
95362306a36Sopenharmony_ci		dmc_pmu = pmu;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	mutex_unlock(&dmc_pmu_mutex);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	return 0;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_cierr_out:
96062306a36Sopenharmony_ci	rockchip_pm_domain_cleanup(pmu);
96162306a36Sopenharmony_ci	mutex_unlock(&dmc_pmu_mutex);
96262306a36Sopenharmony_ci	return error;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic const struct rockchip_domain_info px30_pm_domains[] = {
96662306a36Sopenharmony_ci	[PX30_PD_USB]		= DOMAIN_PX30("usb",      BIT(5),  BIT(5),  BIT(10), false),
96762306a36Sopenharmony_ci	[PX30_PD_SDCARD]	= DOMAIN_PX30("sdcard",   BIT(8),  BIT(8),  BIT(9),  false),
96862306a36Sopenharmony_ci	[PX30_PD_GMAC]		= DOMAIN_PX30("gmac",     BIT(10), BIT(10), BIT(6),  false),
96962306a36Sopenharmony_ci	[PX30_PD_MMC_NAND]	= DOMAIN_PX30("mmc_nand", BIT(11), BIT(11), BIT(5),  false),
97062306a36Sopenharmony_ci	[PX30_PD_VPU]		= DOMAIN_PX30("vpu",      BIT(12), BIT(12), BIT(14), false),
97162306a36Sopenharmony_ci	[PX30_PD_VO]		= DOMAIN_PX30("vo",       BIT(13), BIT(13), BIT(7),  false),
97262306a36Sopenharmony_ci	[PX30_PD_VI]		= DOMAIN_PX30("vi",       BIT(14), BIT(14), BIT(8),  false),
97362306a36Sopenharmony_ci	[PX30_PD_GPU]		= DOMAIN_PX30("gpu",      BIT(15), BIT(15), BIT(2),  false),
97462306a36Sopenharmony_ci};
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_cistatic const struct rockchip_domain_info rv1126_pm_domains[] = {
97762306a36Sopenharmony_ci	[RV1126_PD_VEPU]	= DOMAIN_RV1126("vepu", BIT(2),  BIT(9),  BIT(9), false),
97862306a36Sopenharmony_ci	[RV1126_PD_VI]		= DOMAIN_RV1126("vi", BIT(4),  BIT(6),  BIT(6),  false),
97962306a36Sopenharmony_ci	[RV1126_PD_VO]		= DOMAIN_RV1126("vo", BIT(5),  BIT(7),  BIT(7),  false),
98062306a36Sopenharmony_ci	[RV1126_PD_ISPP]	= DOMAIN_RV1126("ispp", BIT(1), BIT(8), BIT(8),  false),
98162306a36Sopenharmony_ci	[RV1126_PD_VDPU]	= DOMAIN_RV1126("vdpu", BIT(3), BIT(10), BIT(10), false),
98262306a36Sopenharmony_ci	[RV1126_PD_NVM]		= DOMAIN_RV1126("nvm", BIT(7), BIT(11), BIT(11),  false),
98362306a36Sopenharmony_ci	[RV1126_PD_SDIO]	= DOMAIN_RV1126("sdio", BIT(8), BIT(13), BIT(13),  false),
98462306a36Sopenharmony_ci	[RV1126_PD_USB]		= DOMAIN_RV1126("usb", BIT(9), BIT(15), BIT(15),  false),
98562306a36Sopenharmony_ci};
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3036_pm_domains[] = {
98862306a36Sopenharmony_ci	[RK3036_PD_MSCH]	= DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true),
98962306a36Sopenharmony_ci	[RK3036_PD_CORE]	= DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false),
99062306a36Sopenharmony_ci	[RK3036_PD_PERI]	= DOMAIN_RK3036("peri", BIT(12), BIT(18), BIT(25), false),
99162306a36Sopenharmony_ci	[RK3036_PD_VIO]		= DOMAIN_RK3036("vio",  BIT(11), BIT(19), BIT(26), false),
99262306a36Sopenharmony_ci	[RK3036_PD_VPU]		= DOMAIN_RK3036("vpu",  BIT(10), BIT(20), BIT(27), false),
99362306a36Sopenharmony_ci	[RK3036_PD_GPU]		= DOMAIN_RK3036("gpu",  BIT(9),  BIT(21), BIT(28), false),
99462306a36Sopenharmony_ci	[RK3036_PD_SYS]		= DOMAIN_RK3036("sys",  BIT(8),  BIT(22), BIT(29), false),
99562306a36Sopenharmony_ci};
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3066_pm_domains[] = {
99862306a36Sopenharmony_ci	[RK3066_PD_GPU]		= DOMAIN("gpu",   BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
99962306a36Sopenharmony_ci	[RK3066_PD_VIDEO]	= DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
100062306a36Sopenharmony_ci	[RK3066_PD_VIO]		= DOMAIN("vio",   BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
100162306a36Sopenharmony_ci	[RK3066_PD_PERI]	= DOMAIN("peri",  BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
100262306a36Sopenharmony_ci	[RK3066_PD_CPU]		= DOMAIN("cpu",   0,      BIT(5), BIT(1), BIT(26), BIT(31), false),
100362306a36Sopenharmony_ci};
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3128_pm_domains[] = {
100662306a36Sopenharmony_ci	[RK3128_PD_CORE]	= DOMAIN_RK3288("core",  BIT(0), BIT(0), BIT(4), false),
100762306a36Sopenharmony_ci	[RK3128_PD_MSCH]	= DOMAIN_RK3288("msch",  0,      0,      BIT(6), true),
100862306a36Sopenharmony_ci	[RK3128_PD_VIO]		= DOMAIN_RK3288("vio",   BIT(3), BIT(3), BIT(2), false),
100962306a36Sopenharmony_ci	[RK3128_PD_VIDEO]	= DOMAIN_RK3288("video", BIT(2), BIT(2), BIT(1), false),
101062306a36Sopenharmony_ci	[RK3128_PD_GPU]		= DOMAIN_RK3288("gpu",   BIT(1), BIT(1), BIT(3), false),
101162306a36Sopenharmony_ci};
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3188_pm_domains[] = {
101462306a36Sopenharmony_ci	[RK3188_PD_GPU]		= DOMAIN("gpu",   BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
101562306a36Sopenharmony_ci	[RK3188_PD_VIDEO]	= DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
101662306a36Sopenharmony_ci	[RK3188_PD_VIO]		= DOMAIN("vio",   BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
101762306a36Sopenharmony_ci	[RK3188_PD_PERI]	= DOMAIN("peri",  BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
101862306a36Sopenharmony_ci	[RK3188_PD_CPU]		= DOMAIN("cpu",   BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false),
101962306a36Sopenharmony_ci};
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3228_pm_domains[] = {
102262306a36Sopenharmony_ci	[RK3228_PD_CORE]	= DOMAIN_RK3036("core", BIT(0),  BIT(0),  BIT(16), true),
102362306a36Sopenharmony_ci	[RK3228_PD_MSCH]	= DOMAIN_RK3036("msch", BIT(1),  BIT(1),  BIT(17), true),
102462306a36Sopenharmony_ci	[RK3228_PD_BUS]		= DOMAIN_RK3036("bus",  BIT(2),  BIT(2),  BIT(18), true),
102562306a36Sopenharmony_ci	[RK3228_PD_SYS]		= DOMAIN_RK3036("sys",  BIT(3),  BIT(3),  BIT(19), true),
102662306a36Sopenharmony_ci	[RK3228_PD_VIO]		= DOMAIN_RK3036("vio",  BIT(4),  BIT(4),  BIT(20), false),
102762306a36Sopenharmony_ci	[RK3228_PD_VOP]		= DOMAIN_RK3036("vop",  BIT(5),  BIT(5),  BIT(21), false),
102862306a36Sopenharmony_ci	[RK3228_PD_VPU]		= DOMAIN_RK3036("vpu",  BIT(6),  BIT(6),  BIT(22), false),
102962306a36Sopenharmony_ci	[RK3228_PD_RKVDEC]	= DOMAIN_RK3036("vdec", BIT(7),  BIT(7),  BIT(23), false),
103062306a36Sopenharmony_ci	[RK3228_PD_GPU]		= DOMAIN_RK3036("gpu",  BIT(8),  BIT(8),  BIT(24), false),
103162306a36Sopenharmony_ci	[RK3228_PD_PERI]	= DOMAIN_RK3036("peri", BIT(9),  BIT(9),  BIT(25), true),
103262306a36Sopenharmony_ci	[RK3228_PD_GMAC]	= DOMAIN_RK3036("gmac", BIT(10), BIT(10), BIT(26), false),
103362306a36Sopenharmony_ci};
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3288_pm_domains[] = {
103662306a36Sopenharmony_ci	[RK3288_PD_VIO]		= DOMAIN_RK3288("vio",   BIT(7),  BIT(7),  BIT(4), false),
103762306a36Sopenharmony_ci	[RK3288_PD_HEVC]	= DOMAIN_RK3288("hevc",  BIT(14), BIT(10), BIT(9), false),
103862306a36Sopenharmony_ci	[RK3288_PD_VIDEO]	= DOMAIN_RK3288("video", BIT(8),  BIT(8),  BIT(3), false),
103962306a36Sopenharmony_ci	[RK3288_PD_GPU]		= DOMAIN_RK3288("gpu",   BIT(9),  BIT(9),  BIT(2), false),
104062306a36Sopenharmony_ci};
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3328_pm_domains[] = {
104362306a36Sopenharmony_ci	[RK3328_PD_CORE]	= DOMAIN_RK3328("core",  0, BIT(0), BIT(0), false),
104462306a36Sopenharmony_ci	[RK3328_PD_GPU]		= DOMAIN_RK3328("gpu",   0, BIT(1), BIT(1), false),
104562306a36Sopenharmony_ci	[RK3328_PD_BUS]		= DOMAIN_RK3328("bus",   0, BIT(2), BIT(2), true),
104662306a36Sopenharmony_ci	[RK3328_PD_MSCH]	= DOMAIN_RK3328("msch",  0, BIT(3), BIT(3), true),
104762306a36Sopenharmony_ci	[RK3328_PD_PERI]	= DOMAIN_RK3328("peri",  0, BIT(4), BIT(4), true),
104862306a36Sopenharmony_ci	[RK3328_PD_VIDEO]	= DOMAIN_RK3328("video", 0, BIT(5), BIT(5), false),
104962306a36Sopenharmony_ci	[RK3328_PD_HEVC]	= DOMAIN_RK3328("hevc",  0, BIT(6), BIT(6), false),
105062306a36Sopenharmony_ci	[RK3328_PD_VIO]		= DOMAIN_RK3328("vio",   0, BIT(8), BIT(8), false),
105162306a36Sopenharmony_ci	[RK3328_PD_VPU]		= DOMAIN_RK3328("vpu",   0, BIT(9), BIT(9), false),
105262306a36Sopenharmony_ci};
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3366_pm_domains[] = {
105562306a36Sopenharmony_ci	[RK3366_PD_PERI]	= DOMAIN_RK3368("peri",   BIT(10), BIT(10), BIT(6), true),
105662306a36Sopenharmony_ci	[RK3366_PD_VIO]		= DOMAIN_RK3368("vio",    BIT(14), BIT(14), BIT(8), false),
105762306a36Sopenharmony_ci	[RK3366_PD_VIDEO]	= DOMAIN_RK3368("video",  BIT(13), BIT(13), BIT(7), false),
105862306a36Sopenharmony_ci	[RK3366_PD_RKVDEC]	= DOMAIN_RK3368("vdec",   BIT(11), BIT(11), BIT(7), false),
105962306a36Sopenharmony_ci	[RK3366_PD_WIFIBT]	= DOMAIN_RK3368("wifibt", BIT(8),  BIT(8),  BIT(9), false),
106062306a36Sopenharmony_ci	[RK3366_PD_VPU]		= DOMAIN_RK3368("vpu",    BIT(12), BIT(12), BIT(7), false),
106162306a36Sopenharmony_ci	[RK3366_PD_GPU]		= DOMAIN_RK3368("gpu",    BIT(15), BIT(15), BIT(2), false),
106262306a36Sopenharmony_ci};
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3368_pm_domains[] = {
106562306a36Sopenharmony_ci	[RK3368_PD_PERI]	= DOMAIN_RK3368("peri",  BIT(13), BIT(12), BIT(6), true),
106662306a36Sopenharmony_ci	[RK3368_PD_VIO]		= DOMAIN_RK3368("vio",   BIT(15), BIT(14), BIT(8), false),
106762306a36Sopenharmony_ci	[RK3368_PD_VIDEO]	= DOMAIN_RK3368("video", BIT(14), BIT(13), BIT(7), false),
106862306a36Sopenharmony_ci	[RK3368_PD_GPU_0]	= DOMAIN_RK3368("gpu_0", BIT(16), BIT(15), BIT(2), false),
106962306a36Sopenharmony_ci	[RK3368_PD_GPU_1]	= DOMAIN_RK3368("gpu_1", BIT(17), BIT(16), BIT(2), false),
107062306a36Sopenharmony_ci};
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3399_pm_domains[] = {
107362306a36Sopenharmony_ci	[RK3399_PD_TCPD0]	= DOMAIN_RK3399("tcpd0",     BIT(8),  BIT(8),  0,       false),
107462306a36Sopenharmony_ci	[RK3399_PD_TCPD1]	= DOMAIN_RK3399("tcpd1",     BIT(9),  BIT(9),  0,       false),
107562306a36Sopenharmony_ci	[RK3399_PD_CCI]		= DOMAIN_RK3399("cci",       BIT(10), BIT(10), 0,       true),
107662306a36Sopenharmony_ci	[RK3399_PD_CCI0]	= DOMAIN_RK3399("cci0",      0,       0,       BIT(15), true),
107762306a36Sopenharmony_ci	[RK3399_PD_CCI1]	= DOMAIN_RK3399("cci1",      0,       0,       BIT(16), true),
107862306a36Sopenharmony_ci	[RK3399_PD_PERILP]	= DOMAIN_RK3399("perilp",    BIT(11), BIT(11), BIT(1),  true),
107962306a36Sopenharmony_ci	[RK3399_PD_PERIHP]	= DOMAIN_RK3399("perihp",    BIT(12), BIT(12), BIT(2),  true),
108062306a36Sopenharmony_ci	[RK3399_PD_CENTER]	= DOMAIN_RK3399("center",    BIT(13), BIT(13), BIT(14), true),
108162306a36Sopenharmony_ci	[RK3399_PD_VIO]		= DOMAIN_RK3399("vio",       BIT(14), BIT(14), BIT(17), false),
108262306a36Sopenharmony_ci	[RK3399_PD_GPU]		= DOMAIN_RK3399("gpu",       BIT(15), BIT(15), BIT(0),  false),
108362306a36Sopenharmony_ci	[RK3399_PD_VCODEC]	= DOMAIN_RK3399("vcodec",    BIT(16), BIT(16), BIT(3),  false),
108462306a36Sopenharmony_ci	[RK3399_PD_VDU]		= DOMAIN_RK3399("vdu",       BIT(17), BIT(17), BIT(4),  false),
108562306a36Sopenharmony_ci	[RK3399_PD_RGA]		= DOMAIN_RK3399("rga",       BIT(18), BIT(18), BIT(5),  false),
108662306a36Sopenharmony_ci	[RK3399_PD_IEP]		= DOMAIN_RK3399("iep",       BIT(19), BIT(19), BIT(6),  false),
108762306a36Sopenharmony_ci	[RK3399_PD_VO]		= DOMAIN_RK3399("vo",        BIT(20), BIT(20), 0,       false),
108862306a36Sopenharmony_ci	[RK3399_PD_VOPB]	= DOMAIN_RK3399("vopb",      0,       0,       BIT(7),  false),
108962306a36Sopenharmony_ci	[RK3399_PD_VOPL]	= DOMAIN_RK3399("vopl",      0,       0,       BIT(8),  false),
109062306a36Sopenharmony_ci	[RK3399_PD_ISP0]	= DOMAIN_RK3399("isp0",      BIT(22), BIT(22), BIT(9),  false),
109162306a36Sopenharmony_ci	[RK3399_PD_ISP1]	= DOMAIN_RK3399("isp1",      BIT(23), BIT(23), BIT(10), false),
109262306a36Sopenharmony_ci	[RK3399_PD_HDCP]	= DOMAIN_RK3399("hdcp",      BIT(24), BIT(24), BIT(11), false),
109362306a36Sopenharmony_ci	[RK3399_PD_GMAC]	= DOMAIN_RK3399("gmac",      BIT(25), BIT(25), BIT(23), true),
109462306a36Sopenharmony_ci	[RK3399_PD_EMMC]	= DOMAIN_RK3399("emmc",      BIT(26), BIT(26), BIT(24), true),
109562306a36Sopenharmony_ci	[RK3399_PD_USB3]	= DOMAIN_RK3399("usb3",      BIT(27), BIT(27), BIT(12), true),
109662306a36Sopenharmony_ci	[RK3399_PD_EDP]		= DOMAIN_RK3399("edp",       BIT(28), BIT(28), BIT(22), false),
109762306a36Sopenharmony_ci	[RK3399_PD_GIC]		= DOMAIN_RK3399("gic",       BIT(29), BIT(29), BIT(27), true),
109862306a36Sopenharmony_ci	[RK3399_PD_SD]		= DOMAIN_RK3399("sd",        BIT(30), BIT(30), BIT(28), true),
109962306a36Sopenharmony_ci	[RK3399_PD_SDIOAUDIO]	= DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true),
110062306a36Sopenharmony_ci};
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3568_pm_domains[] = {
110362306a36Sopenharmony_ci	[RK3568_PD_NPU]		= DOMAIN_RK3568("npu",  BIT(1), BIT(2),  false),
110462306a36Sopenharmony_ci	[RK3568_PD_GPU]		= DOMAIN_RK3568("gpu",  BIT(0), BIT(1),  false),
110562306a36Sopenharmony_ci	[RK3568_PD_VI]		= DOMAIN_RK3568("vi",   BIT(6), BIT(3),  false),
110662306a36Sopenharmony_ci	[RK3568_PD_VO]		= DOMAIN_RK3568("vo",   BIT(7), BIT(4),  false),
110762306a36Sopenharmony_ci	[RK3568_PD_RGA]		= DOMAIN_RK3568("rga",  BIT(5), BIT(5),  false),
110862306a36Sopenharmony_ci	[RK3568_PD_VPU]		= DOMAIN_RK3568("vpu",  BIT(2), BIT(6),  false),
110962306a36Sopenharmony_ci	[RK3568_PD_RKVDEC]	= DOMAIN_RK3568("vdec", BIT(4), BIT(8),  false),
111062306a36Sopenharmony_ci	[RK3568_PD_RKVENC]	= DOMAIN_RK3568("venc", BIT(3), BIT(7),  false),
111162306a36Sopenharmony_ci	[RK3568_PD_PIPE]	= DOMAIN_RK3568("pipe", BIT(8), BIT(11), false),
111262306a36Sopenharmony_ci};
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cistatic const struct rockchip_domain_info rk3588_pm_domains[] = {
111562306a36Sopenharmony_ci	[RK3588_PD_GPU]		= DOMAIN_RK3588("gpu",     0x0, BIT(0),  0,       0x0, 0,       BIT(1),  0x0, BIT(0),  BIT(0),  false),
111662306a36Sopenharmony_ci	[RK3588_PD_NPU]		= DOMAIN_RK3588("npu",     0x0, BIT(1),  BIT(1),  0x0, 0,       0,       0x0, 0,       0,       false),
111762306a36Sopenharmony_ci	[RK3588_PD_VCODEC]	= DOMAIN_RK3588("vcodec",  0x0, BIT(2),  BIT(2),  0x0, 0,       0,       0x0, 0,       0,       false),
111862306a36Sopenharmony_ci	[RK3588_PD_NPUTOP]	= DOMAIN_RK3588("nputop",  0x0, BIT(3),  0,       0x0, BIT(11), BIT(2),  0x0, BIT(1),  BIT(1),  false),
111962306a36Sopenharmony_ci	[RK3588_PD_NPU1]	= DOMAIN_RK3588("npu1",    0x0, BIT(4),  0,       0x0, BIT(12), BIT(3),  0x0, BIT(2),  BIT(2),  false),
112062306a36Sopenharmony_ci	[RK3588_PD_NPU2]	= DOMAIN_RK3588("npu2",    0x0, BIT(5),  0,       0x0, BIT(13), BIT(4),  0x0, BIT(3),  BIT(3),  false),
112162306a36Sopenharmony_ci	[RK3588_PD_VENC0]	= DOMAIN_RK3588("venc0",   0x0, BIT(6),  0,       0x0, BIT(14), BIT(5),  0x0, BIT(4),  BIT(4),  false),
112262306a36Sopenharmony_ci	[RK3588_PD_VENC1]	= DOMAIN_RK3588("venc1",   0x0, BIT(7),  0,       0x0, BIT(15), BIT(6),  0x0, BIT(5),  BIT(5),  false),
112362306a36Sopenharmony_ci	[RK3588_PD_RKVDEC0]	= DOMAIN_RK3588("rkvdec0", 0x0, BIT(8),  0,       0x0, BIT(16), BIT(7),  0x0, BIT(6),  BIT(6),  false),
112462306a36Sopenharmony_ci	[RK3588_PD_RKVDEC1]	= DOMAIN_RK3588("rkvdec1", 0x0, BIT(9),  0,       0x0, BIT(17), BIT(8),  0x0, BIT(7),  BIT(7),  false),
112562306a36Sopenharmony_ci	[RK3588_PD_VDPU]	= DOMAIN_RK3588("vdpu",    0x0, BIT(10), 0,       0x0, BIT(18), BIT(9),  0x0, BIT(8),  BIT(8),  false),
112662306a36Sopenharmony_ci	[RK3588_PD_RGA30]	= DOMAIN_RK3588("rga30",   0x0, BIT(11), 0,       0x0, BIT(19), BIT(10), 0x0, 0,       0,       false),
112762306a36Sopenharmony_ci	[RK3588_PD_AV1]		= DOMAIN_RK3588("av1",     0x0, BIT(12), 0,       0x0, BIT(20), BIT(11), 0x0, BIT(9),  BIT(9),  false),
112862306a36Sopenharmony_ci	[RK3588_PD_VI]		= DOMAIN_RK3588("vi",      0x0, BIT(13), 0,       0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false),
112962306a36Sopenharmony_ci	[RK3588_PD_FEC]		= DOMAIN_RK3588("fec",     0x0, BIT(14), 0,       0x0, BIT(22), BIT(13), 0x0, 0,       0,       false),
113062306a36Sopenharmony_ci	[RK3588_PD_ISP1]	= DOMAIN_RK3588("isp1",    0x0, BIT(15), 0,       0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false),
113162306a36Sopenharmony_ci	[RK3588_PD_RGA31]	= DOMAIN_RK3588("rga31",   0x4, BIT(0),  0,       0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false),
113262306a36Sopenharmony_ci	[RK3588_PD_VOP]		= DOMAIN_RK3588("vop",     0x4, BIT(1),  0,       0x0, BIT(25), BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false),
113362306a36Sopenharmony_ci	[RK3588_PD_VO0]		= DOMAIN_RK3588("vo0",     0x4, BIT(2),  0,       0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false),
113462306a36Sopenharmony_ci	[RK3588_PD_VO1]		= DOMAIN_RK3588("vo1",     0x4, BIT(3),  0,       0x0, BIT(27), BIT(18), 0x4, BIT(0),  BIT(16), false),
113562306a36Sopenharmony_ci	[RK3588_PD_AUDIO]	= DOMAIN_RK3588("audio",   0x4, BIT(4),  0,       0x0, BIT(28), BIT(19), 0x4, BIT(1),  BIT(17), false),
113662306a36Sopenharmony_ci	[RK3588_PD_PHP]		= DOMAIN_RK3588("php",     0x4, BIT(5),  0,       0x0, BIT(29), BIT(20), 0x4, BIT(5),  BIT(21), false),
113762306a36Sopenharmony_ci	[RK3588_PD_GMAC]	= DOMAIN_RK3588("gmac",    0x4, BIT(6),  0,       0x0, BIT(30), BIT(21), 0x0, 0,       0,       false),
113862306a36Sopenharmony_ci	[RK3588_PD_PCIE]	= DOMAIN_RK3588("pcie",    0x4, BIT(7),  0,       0x0, BIT(31), BIT(22), 0x0, 0,       0,       true),
113962306a36Sopenharmony_ci	[RK3588_PD_NVM]		= DOMAIN_RK3588("nvm",     0x4, BIT(8),  BIT(24), 0x4, 0,       0,       0x4, BIT(2),  BIT(18), false),
114062306a36Sopenharmony_ci	[RK3588_PD_NVM0]	= DOMAIN_RK3588("nvm0",    0x4, BIT(9),  0,       0x4, BIT(1),  BIT(23), 0x0, 0,       0,       false),
114162306a36Sopenharmony_ci	[RK3588_PD_SDIO]	= DOMAIN_RK3588("sdio",    0x4, BIT(10), 0,       0x4, BIT(2),  BIT(24), 0x4, BIT(3),  BIT(19), false),
114262306a36Sopenharmony_ci	[RK3588_PD_USB]		= DOMAIN_RK3588("usb",     0x4, BIT(11), 0,       0x4, BIT(3),  BIT(25), 0x4, BIT(4),  BIT(20), true),
114362306a36Sopenharmony_ci	[RK3588_PD_SDMMC]	= DOMAIN_RK3588("sdmmc",   0x4, BIT(13), 0,       0x4, BIT(5),  BIT(26), 0x0, 0,       0,       false),
114462306a36Sopenharmony_ci};
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic const struct rockchip_pmu_info px30_pmu = {
114762306a36Sopenharmony_ci	.pwr_offset = 0x18,
114862306a36Sopenharmony_ci	.status_offset = 0x20,
114962306a36Sopenharmony_ci	.req_offset = 0x64,
115062306a36Sopenharmony_ci	.idle_offset = 0x6c,
115162306a36Sopenharmony_ci	.ack_offset = 0x6c,
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(px30_pm_domains),
115462306a36Sopenharmony_ci	.domain_info = px30_pm_domains,
115562306a36Sopenharmony_ci};
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3036_pmu = {
115862306a36Sopenharmony_ci	.req_offset = 0x148,
115962306a36Sopenharmony_ci	.idle_offset = 0x14c,
116062306a36Sopenharmony_ci	.ack_offset = 0x14c,
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3036_pm_domains),
116362306a36Sopenharmony_ci	.domain_info = rk3036_pm_domains,
116462306a36Sopenharmony_ci};
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3066_pmu = {
116762306a36Sopenharmony_ci	.pwr_offset = 0x08,
116862306a36Sopenharmony_ci	.status_offset = 0x0c,
116962306a36Sopenharmony_ci	.req_offset = 0x38, /* PMU_MISC_CON1 */
117062306a36Sopenharmony_ci	.idle_offset = 0x0c,
117162306a36Sopenharmony_ci	.ack_offset = 0x0c,
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3066_pm_domains),
117462306a36Sopenharmony_ci	.domain_info = rk3066_pm_domains,
117562306a36Sopenharmony_ci};
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3128_pmu = {
117862306a36Sopenharmony_ci	.pwr_offset = 0x04,
117962306a36Sopenharmony_ci	.status_offset = 0x08,
118062306a36Sopenharmony_ci	.req_offset = 0x0c,
118162306a36Sopenharmony_ci	.idle_offset = 0x10,
118262306a36Sopenharmony_ci	.ack_offset = 0x10,
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3128_pm_domains),
118562306a36Sopenharmony_ci	.domain_info = rk3128_pm_domains,
118662306a36Sopenharmony_ci};
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3188_pmu = {
118962306a36Sopenharmony_ci	.pwr_offset = 0x08,
119062306a36Sopenharmony_ci	.status_offset = 0x0c,
119162306a36Sopenharmony_ci	.req_offset = 0x38, /* PMU_MISC_CON1 */
119262306a36Sopenharmony_ci	.idle_offset = 0x0c,
119362306a36Sopenharmony_ci	.ack_offset = 0x0c,
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3188_pm_domains),
119662306a36Sopenharmony_ci	.domain_info = rk3188_pm_domains,
119762306a36Sopenharmony_ci};
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3228_pmu = {
120062306a36Sopenharmony_ci	.req_offset = 0x40c,
120162306a36Sopenharmony_ci	.idle_offset = 0x488,
120262306a36Sopenharmony_ci	.ack_offset = 0x488,
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3228_pm_domains),
120562306a36Sopenharmony_ci	.domain_info = rk3228_pm_domains,
120662306a36Sopenharmony_ci};
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3288_pmu = {
120962306a36Sopenharmony_ci	.pwr_offset = 0x08,
121062306a36Sopenharmony_ci	.status_offset = 0x0c,
121162306a36Sopenharmony_ci	.req_offset = 0x10,
121262306a36Sopenharmony_ci	.idle_offset = 0x14,
121362306a36Sopenharmony_ci	.ack_offset = 0x14,
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	.core_pwrcnt_offset = 0x34,
121662306a36Sopenharmony_ci	.gpu_pwrcnt_offset = 0x3c,
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	.core_power_transition_time = 24, /* 1us */
121962306a36Sopenharmony_ci	.gpu_power_transition_time = 24, /* 1us */
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3288_pm_domains),
122262306a36Sopenharmony_ci	.domain_info = rk3288_pm_domains,
122362306a36Sopenharmony_ci};
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3328_pmu = {
122662306a36Sopenharmony_ci	.req_offset = 0x414,
122762306a36Sopenharmony_ci	.idle_offset = 0x484,
122862306a36Sopenharmony_ci	.ack_offset = 0x484,
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3328_pm_domains),
123162306a36Sopenharmony_ci	.domain_info = rk3328_pm_domains,
123262306a36Sopenharmony_ci};
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3366_pmu = {
123562306a36Sopenharmony_ci	.pwr_offset = 0x0c,
123662306a36Sopenharmony_ci	.status_offset = 0x10,
123762306a36Sopenharmony_ci	.req_offset = 0x3c,
123862306a36Sopenharmony_ci	.idle_offset = 0x40,
123962306a36Sopenharmony_ci	.ack_offset = 0x40,
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	.core_pwrcnt_offset = 0x48,
124262306a36Sopenharmony_ci	.gpu_pwrcnt_offset = 0x50,
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	.core_power_transition_time = 24,
124562306a36Sopenharmony_ci	.gpu_power_transition_time = 24,
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3366_pm_domains),
124862306a36Sopenharmony_ci	.domain_info = rk3366_pm_domains,
124962306a36Sopenharmony_ci};
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3368_pmu = {
125262306a36Sopenharmony_ci	.pwr_offset = 0x0c,
125362306a36Sopenharmony_ci	.status_offset = 0x10,
125462306a36Sopenharmony_ci	.req_offset = 0x3c,
125562306a36Sopenharmony_ci	.idle_offset = 0x40,
125662306a36Sopenharmony_ci	.ack_offset = 0x40,
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	.core_pwrcnt_offset = 0x48,
125962306a36Sopenharmony_ci	.gpu_pwrcnt_offset = 0x50,
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	.core_power_transition_time = 24,
126262306a36Sopenharmony_ci	.gpu_power_transition_time = 24,
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3368_pm_domains),
126562306a36Sopenharmony_ci	.domain_info = rk3368_pm_domains,
126662306a36Sopenharmony_ci};
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3399_pmu = {
126962306a36Sopenharmony_ci	.pwr_offset = 0x14,
127062306a36Sopenharmony_ci	.status_offset = 0x18,
127162306a36Sopenharmony_ci	.req_offset = 0x60,
127262306a36Sopenharmony_ci	.idle_offset = 0x64,
127362306a36Sopenharmony_ci	.ack_offset = 0x68,
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	/* ARM Trusted Firmware manages power transition times */
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3399_pm_domains),
127862306a36Sopenharmony_ci	.domain_info = rk3399_pm_domains,
127962306a36Sopenharmony_ci};
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3568_pmu = {
128262306a36Sopenharmony_ci	.pwr_offset = 0xa0,
128362306a36Sopenharmony_ci	.status_offset = 0x98,
128462306a36Sopenharmony_ci	.req_offset = 0x50,
128562306a36Sopenharmony_ci	.idle_offset = 0x68,
128662306a36Sopenharmony_ci	.ack_offset = 0x60,
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3568_pm_domains),
128962306a36Sopenharmony_ci	.domain_info = rk3568_pm_domains,
129062306a36Sopenharmony_ci};
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cistatic const struct rockchip_pmu_info rk3588_pmu = {
129362306a36Sopenharmony_ci	.pwr_offset = 0x14c,
129462306a36Sopenharmony_ci	.status_offset = 0x180,
129562306a36Sopenharmony_ci	.req_offset = 0x10c,
129662306a36Sopenharmony_ci	.idle_offset = 0x120,
129762306a36Sopenharmony_ci	.ack_offset = 0x118,
129862306a36Sopenharmony_ci	.mem_pwr_offset = 0x1a0,
129962306a36Sopenharmony_ci	.chain_status_offset = 0x1f0,
130062306a36Sopenharmony_ci	.mem_status_offset = 0x1f8,
130162306a36Sopenharmony_ci	.repair_status_offset = 0x290,
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3588_pm_domains),
130462306a36Sopenharmony_ci	.domain_info = rk3588_pm_domains,
130562306a36Sopenharmony_ci};
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_cistatic const struct rockchip_pmu_info rv1126_pmu = {
130862306a36Sopenharmony_ci	.pwr_offset = 0x110,
130962306a36Sopenharmony_ci	.status_offset = 0x108,
131062306a36Sopenharmony_ci	.req_offset = 0xc0,
131162306a36Sopenharmony_ci	.idle_offset = 0xd8,
131262306a36Sopenharmony_ci	.ack_offset = 0xd0,
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	.num_domains = ARRAY_SIZE(rv1126_pm_domains),
131562306a36Sopenharmony_ci	.domain_info = rv1126_pm_domains,
131662306a36Sopenharmony_ci};
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_cistatic const struct of_device_id rockchip_pm_domain_dt_match[] = {
131962306a36Sopenharmony_ci	{
132062306a36Sopenharmony_ci		.compatible = "rockchip,px30-power-controller",
132162306a36Sopenharmony_ci		.data = (void *)&px30_pmu,
132262306a36Sopenharmony_ci	},
132362306a36Sopenharmony_ci	{
132462306a36Sopenharmony_ci		.compatible = "rockchip,rk3036-power-controller",
132562306a36Sopenharmony_ci		.data = (void *)&rk3036_pmu,
132662306a36Sopenharmony_ci	},
132762306a36Sopenharmony_ci	{
132862306a36Sopenharmony_ci		.compatible = "rockchip,rk3066-power-controller",
132962306a36Sopenharmony_ci		.data = (void *)&rk3066_pmu,
133062306a36Sopenharmony_ci	},
133162306a36Sopenharmony_ci	{
133262306a36Sopenharmony_ci		.compatible = "rockchip,rk3128-power-controller",
133362306a36Sopenharmony_ci		.data = (void *)&rk3128_pmu,
133462306a36Sopenharmony_ci	},
133562306a36Sopenharmony_ci	{
133662306a36Sopenharmony_ci		.compatible = "rockchip,rk3188-power-controller",
133762306a36Sopenharmony_ci		.data = (void *)&rk3188_pmu,
133862306a36Sopenharmony_ci	},
133962306a36Sopenharmony_ci	{
134062306a36Sopenharmony_ci		.compatible = "rockchip,rk3228-power-controller",
134162306a36Sopenharmony_ci		.data = (void *)&rk3228_pmu,
134262306a36Sopenharmony_ci	},
134362306a36Sopenharmony_ci	{
134462306a36Sopenharmony_ci		.compatible = "rockchip,rk3288-power-controller",
134562306a36Sopenharmony_ci		.data = (void *)&rk3288_pmu,
134662306a36Sopenharmony_ci	},
134762306a36Sopenharmony_ci	{
134862306a36Sopenharmony_ci		.compatible = "rockchip,rk3328-power-controller",
134962306a36Sopenharmony_ci		.data = (void *)&rk3328_pmu,
135062306a36Sopenharmony_ci	},
135162306a36Sopenharmony_ci	{
135262306a36Sopenharmony_ci		.compatible = "rockchip,rk3366-power-controller",
135362306a36Sopenharmony_ci		.data = (void *)&rk3366_pmu,
135462306a36Sopenharmony_ci	},
135562306a36Sopenharmony_ci	{
135662306a36Sopenharmony_ci		.compatible = "rockchip,rk3368-power-controller",
135762306a36Sopenharmony_ci		.data = (void *)&rk3368_pmu,
135862306a36Sopenharmony_ci	},
135962306a36Sopenharmony_ci	{
136062306a36Sopenharmony_ci		.compatible = "rockchip,rk3399-power-controller",
136162306a36Sopenharmony_ci		.data = (void *)&rk3399_pmu,
136262306a36Sopenharmony_ci	},
136362306a36Sopenharmony_ci	{
136462306a36Sopenharmony_ci		.compatible = "rockchip,rk3568-power-controller",
136562306a36Sopenharmony_ci		.data = (void *)&rk3568_pmu,
136662306a36Sopenharmony_ci	},
136762306a36Sopenharmony_ci	{
136862306a36Sopenharmony_ci		.compatible = "rockchip,rk3588-power-controller",
136962306a36Sopenharmony_ci		.data = (void *)&rk3588_pmu,
137062306a36Sopenharmony_ci	},
137162306a36Sopenharmony_ci	{
137262306a36Sopenharmony_ci		.compatible = "rockchip,rv1126-power-controller",
137362306a36Sopenharmony_ci		.data = (void *)&rv1126_pmu,
137462306a36Sopenharmony_ci	},
137562306a36Sopenharmony_ci	{ /* sentinel */ },
137662306a36Sopenharmony_ci};
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic struct platform_driver rockchip_pm_domain_driver = {
137962306a36Sopenharmony_ci	.probe = rockchip_pm_domain_probe,
138062306a36Sopenharmony_ci	.driver = {
138162306a36Sopenharmony_ci		.name   = "rockchip-pm-domain",
138262306a36Sopenharmony_ci		.of_match_table = rockchip_pm_domain_dt_match,
138362306a36Sopenharmony_ci		/*
138462306a36Sopenharmony_ci		 * We can't forcibly eject devices from the power
138562306a36Sopenharmony_ci		 * domain, so we can't really remove power domains
138662306a36Sopenharmony_ci		 * once they were added.
138762306a36Sopenharmony_ci		 */
138862306a36Sopenharmony_ci		.suppress_bind_attrs = true,
138962306a36Sopenharmony_ci	},
139062306a36Sopenharmony_ci};
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic int __init rockchip_pm_domain_drv_register(void)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	return platform_driver_register(&rockchip_pm_domain_driver);
139562306a36Sopenharmony_ci}
139662306a36Sopenharmony_cipostcore_initcall(rockchip_pm_domain_drv_register);
1397