162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/err.h>
562306a36Sopenharmony_ci#include <linux/init.h>
662306a36Sopenharmony_ci#include <linux/kernel.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/mutex.h>
962306a36Sopenharmony_ci#include <linux/pm_domain.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci#include <linux/pm_opp.h>
1462306a36Sopenharmony_ci#include <soc/qcom/cmd-db.h>
1562306a36Sopenharmony_ci#include <soc/qcom/rpmh.h>
1662306a36Sopenharmony_ci#include <dt-bindings/power/qcom-rpmpd.h>
1762306a36Sopenharmony_ci#include <dt-bindings/power/qcom,rpmhpd.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define RPMH_ARC_MAX_LEVELS	16
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/**
2462306a36Sopenharmony_ci * struct rpmhpd - top level RPMh power domain resource data structure
2562306a36Sopenharmony_ci * @dev:		rpmh power domain controller device
2662306a36Sopenharmony_ci * @pd:			generic_pm_domain corresponding to the power domain
2762306a36Sopenharmony_ci * @parent:		generic_pm_domain corresponding to the parent's power domain
2862306a36Sopenharmony_ci * @peer:		A peer power domain in case Active only Voting is
2962306a36Sopenharmony_ci *			supported
3062306a36Sopenharmony_ci * @active_only:	True if it represents an Active only peer
3162306a36Sopenharmony_ci * @corner:		current corner
3262306a36Sopenharmony_ci * @active_corner:	current active corner
3362306a36Sopenharmony_ci * @enable_corner:	lowest non-zero corner
3462306a36Sopenharmony_ci * @level:		An array of level (vlvl) to corner (hlvl) mappings
3562306a36Sopenharmony_ci *			derived from cmd-db
3662306a36Sopenharmony_ci * @level_count:	Number of levels supported by the power domain. max
3762306a36Sopenharmony_ci *			being 16 (0 - 15)
3862306a36Sopenharmony_ci * @enabled:		true if the power domain is enabled
3962306a36Sopenharmony_ci * @res_name:		Resource name used for cmd-db lookup
4062306a36Sopenharmony_ci * @addr:		Resource address as looped up using resource name from
4162306a36Sopenharmony_ci *			cmd-db
4262306a36Sopenharmony_ci * @state_synced:	Indicator that sync_state has been invoked for the rpmhpd resource
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_cistruct rpmhpd {
4562306a36Sopenharmony_ci	struct device	*dev;
4662306a36Sopenharmony_ci	struct generic_pm_domain pd;
4762306a36Sopenharmony_ci	struct generic_pm_domain *parent;
4862306a36Sopenharmony_ci	struct rpmhpd	*peer;
4962306a36Sopenharmony_ci	const bool	active_only;
5062306a36Sopenharmony_ci	unsigned int	corner;
5162306a36Sopenharmony_ci	unsigned int	active_corner;
5262306a36Sopenharmony_ci	unsigned int	enable_corner;
5362306a36Sopenharmony_ci	u32		level[RPMH_ARC_MAX_LEVELS];
5462306a36Sopenharmony_ci	size_t		level_count;
5562306a36Sopenharmony_ci	bool		enabled;
5662306a36Sopenharmony_ci	const char	*res_name;
5762306a36Sopenharmony_ci	u32		addr;
5862306a36Sopenharmony_ci	bool		state_synced;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct rpmhpd_desc {
6262306a36Sopenharmony_ci	struct rpmhpd **rpmhpds;
6362306a36Sopenharmony_ci	size_t num_pds;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic DEFINE_MUTEX(rpmhpd_lock);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* RPMH powerdomains */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic struct rpmhpd cx_ao;
7162306a36Sopenharmony_cistatic struct rpmhpd mx;
7262306a36Sopenharmony_cistatic struct rpmhpd mx_ao;
7362306a36Sopenharmony_cistatic struct rpmhpd cx = {
7462306a36Sopenharmony_ci	.pd = { .name = "cx", },
7562306a36Sopenharmony_ci	.peer = &cx_ao,
7662306a36Sopenharmony_ci	.res_name = "cx.lvl",
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic struct rpmhpd cx_ao = {
8062306a36Sopenharmony_ci	.pd = { .name = "cx_ao", },
8162306a36Sopenharmony_ci	.active_only = true,
8262306a36Sopenharmony_ci	.peer = &cx,
8362306a36Sopenharmony_ci	.res_name = "cx.lvl",
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic struct rpmhpd cx_ao_w_mx_parent;
8762306a36Sopenharmony_cistatic struct rpmhpd cx_w_mx_parent = {
8862306a36Sopenharmony_ci	.pd = { .name = "cx", },
8962306a36Sopenharmony_ci	.peer = &cx_ao_w_mx_parent,
9062306a36Sopenharmony_ci	.parent = &mx.pd,
9162306a36Sopenharmony_ci	.res_name = "cx.lvl",
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic struct rpmhpd cx_ao_w_mx_parent = {
9562306a36Sopenharmony_ci	.pd = { .name = "cx_ao", },
9662306a36Sopenharmony_ci	.active_only = true,
9762306a36Sopenharmony_ci	.peer = &cx_w_mx_parent,
9862306a36Sopenharmony_ci	.parent = &mx_ao.pd,
9962306a36Sopenharmony_ci	.res_name = "cx.lvl",
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic struct rpmhpd ebi = {
10362306a36Sopenharmony_ci	.pd = { .name = "ebi", },
10462306a36Sopenharmony_ci	.res_name = "ebi.lvl",
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic struct rpmhpd gfx = {
10862306a36Sopenharmony_ci	.pd = { .name = "gfx", },
10962306a36Sopenharmony_ci	.res_name = "gfx.lvl",
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic struct rpmhpd lcx = {
11362306a36Sopenharmony_ci	.pd = { .name = "lcx", },
11462306a36Sopenharmony_ci	.res_name = "lcx.lvl",
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic struct rpmhpd lmx = {
11862306a36Sopenharmony_ci	.pd = { .name = "lmx", },
11962306a36Sopenharmony_ci	.res_name = "lmx.lvl",
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic struct rpmhpd mmcx_ao;
12362306a36Sopenharmony_cistatic struct rpmhpd mmcx = {
12462306a36Sopenharmony_ci	.pd = { .name = "mmcx", },
12562306a36Sopenharmony_ci	.peer = &mmcx_ao,
12662306a36Sopenharmony_ci	.res_name = "mmcx.lvl",
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic struct rpmhpd mmcx_ao = {
13062306a36Sopenharmony_ci	.pd = { .name = "mmcx_ao", },
13162306a36Sopenharmony_ci	.active_only = true,
13262306a36Sopenharmony_ci	.peer = &mmcx,
13362306a36Sopenharmony_ci	.res_name = "mmcx.lvl",
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic struct rpmhpd mmcx_ao_w_cx_parent;
13762306a36Sopenharmony_cistatic struct rpmhpd mmcx_w_cx_parent = {
13862306a36Sopenharmony_ci	.pd = { .name = "mmcx", },
13962306a36Sopenharmony_ci	.peer = &mmcx_ao_w_cx_parent,
14062306a36Sopenharmony_ci	.parent = &cx.pd,
14162306a36Sopenharmony_ci	.res_name = "mmcx.lvl",
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic struct rpmhpd mmcx_ao_w_cx_parent = {
14562306a36Sopenharmony_ci	.pd = { .name = "mmcx_ao", },
14662306a36Sopenharmony_ci	.active_only = true,
14762306a36Sopenharmony_ci	.peer = &mmcx_w_cx_parent,
14862306a36Sopenharmony_ci	.parent = &cx_ao.pd,
14962306a36Sopenharmony_ci	.res_name = "mmcx.lvl",
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic struct rpmhpd mss = {
15362306a36Sopenharmony_ci	.pd = { .name = "mss", },
15462306a36Sopenharmony_ci	.res_name = "mss.lvl",
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic struct rpmhpd mx_ao;
15862306a36Sopenharmony_cistatic struct rpmhpd mx = {
15962306a36Sopenharmony_ci	.pd = { .name = "mx", },
16062306a36Sopenharmony_ci	.peer = &mx_ao,
16162306a36Sopenharmony_ci	.res_name = "mx.lvl",
16262306a36Sopenharmony_ci};
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic struct rpmhpd mx_ao = {
16562306a36Sopenharmony_ci	.pd = { .name = "mx_ao", },
16662306a36Sopenharmony_ci	.active_only = true,
16762306a36Sopenharmony_ci	.peer = &mx,
16862306a36Sopenharmony_ci	.res_name = "mx.lvl",
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic struct rpmhpd mxc_ao;
17262306a36Sopenharmony_cistatic struct rpmhpd mxc = {
17362306a36Sopenharmony_ci	.pd = { .name = "mxc", },
17462306a36Sopenharmony_ci	.peer = &mxc_ao,
17562306a36Sopenharmony_ci	.res_name = "mxc.lvl",
17662306a36Sopenharmony_ci};
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic struct rpmhpd mxc_ao = {
17962306a36Sopenharmony_ci	.pd = { .name = "mxc_ao", },
18062306a36Sopenharmony_ci	.active_only = true,
18162306a36Sopenharmony_ci	.peer = &mxc,
18262306a36Sopenharmony_ci	.res_name = "mxc.lvl",
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic struct rpmhpd nsp = {
18662306a36Sopenharmony_ci	.pd = { .name = "nsp", },
18762306a36Sopenharmony_ci	.res_name = "nsp.lvl",
18862306a36Sopenharmony_ci};
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic struct rpmhpd nsp0 = {
19162306a36Sopenharmony_ci	.pd = { .name = "nsp0", },
19262306a36Sopenharmony_ci	.res_name = "nsp0.lvl",
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic struct rpmhpd nsp1 = {
19662306a36Sopenharmony_ci	.pd = { .name = "nsp1", },
19762306a36Sopenharmony_ci	.res_name = "nsp1.lvl",
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic struct rpmhpd qphy = {
20162306a36Sopenharmony_ci	.pd = { .name = "qphy", },
20262306a36Sopenharmony_ci	.res_name = "qphy.lvl",
20362306a36Sopenharmony_ci};
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci/* SA8540P RPMH powerdomains */
20662306a36Sopenharmony_cistatic struct rpmhpd *sa8540p_rpmhpds[] = {
20762306a36Sopenharmony_ci	[SC8280XP_CX] = &cx,
20862306a36Sopenharmony_ci	[SC8280XP_CX_AO] = &cx_ao,
20962306a36Sopenharmony_ci	[SC8280XP_EBI] = &ebi,
21062306a36Sopenharmony_ci	[SC8280XP_LCX] = &lcx,
21162306a36Sopenharmony_ci	[SC8280XP_LMX] = &lmx,
21262306a36Sopenharmony_ci	[SC8280XP_MMCX] = &mmcx,
21362306a36Sopenharmony_ci	[SC8280XP_MMCX_AO] = &mmcx_ao,
21462306a36Sopenharmony_ci	[SC8280XP_MX] = &mx,
21562306a36Sopenharmony_ci	[SC8280XP_MX_AO] = &mx_ao,
21662306a36Sopenharmony_ci	[SC8280XP_NSP] = &nsp,
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic const struct rpmhpd_desc sa8540p_desc = {
22062306a36Sopenharmony_ci	.rpmhpds = sa8540p_rpmhpds,
22162306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sa8540p_rpmhpds),
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/* SA8775P RPMH power domains */
22562306a36Sopenharmony_cistatic struct rpmhpd *sa8775p_rpmhpds[] = {
22662306a36Sopenharmony_ci	[SA8775P_CX] = &cx,
22762306a36Sopenharmony_ci	[SA8775P_CX_AO] = &cx_ao,
22862306a36Sopenharmony_ci	[SA8775P_EBI] = &ebi,
22962306a36Sopenharmony_ci	[SA8775P_GFX] = &gfx,
23062306a36Sopenharmony_ci	[SA8775P_LCX] = &lcx,
23162306a36Sopenharmony_ci	[SA8775P_LMX] = &lmx,
23262306a36Sopenharmony_ci	[SA8775P_MMCX] = &mmcx,
23362306a36Sopenharmony_ci	[SA8775P_MMCX_AO] = &mmcx_ao,
23462306a36Sopenharmony_ci	[SA8775P_MXC] = &mxc,
23562306a36Sopenharmony_ci	[SA8775P_MXC_AO] = &mxc_ao,
23662306a36Sopenharmony_ci	[SA8775P_MX] = &mx,
23762306a36Sopenharmony_ci	[SA8775P_MX_AO] = &mx_ao,
23862306a36Sopenharmony_ci	[SA8775P_NSP0] = &nsp0,
23962306a36Sopenharmony_ci	[SA8775P_NSP1] = &nsp1,
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic const struct rpmhpd_desc sa8775p_desc = {
24362306a36Sopenharmony_ci	.rpmhpds = sa8775p_rpmhpds,
24462306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sa8775p_rpmhpds),
24562306a36Sopenharmony_ci};
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/* SDM670 RPMH powerdomains */
24862306a36Sopenharmony_cistatic struct rpmhpd *sdm670_rpmhpds[] = {
24962306a36Sopenharmony_ci	[SDM670_CX] = &cx_w_mx_parent,
25062306a36Sopenharmony_ci	[SDM670_CX_AO] = &cx_ao_w_mx_parent,
25162306a36Sopenharmony_ci	[SDM670_GFX] = &gfx,
25262306a36Sopenharmony_ci	[SDM670_LCX] = &lcx,
25362306a36Sopenharmony_ci	[SDM670_LMX] = &lmx,
25462306a36Sopenharmony_ci	[SDM670_MSS] = &mss,
25562306a36Sopenharmony_ci	[SDM670_MX] = &mx,
25662306a36Sopenharmony_ci	[SDM670_MX_AO] = &mx_ao,
25762306a36Sopenharmony_ci};
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic const struct rpmhpd_desc sdm670_desc = {
26062306a36Sopenharmony_ci	.rpmhpds = sdm670_rpmhpds,
26162306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sdm670_rpmhpds),
26262306a36Sopenharmony_ci};
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/* SDM845 RPMH powerdomains */
26562306a36Sopenharmony_cistatic struct rpmhpd *sdm845_rpmhpds[] = {
26662306a36Sopenharmony_ci	[SDM845_CX] = &cx_w_mx_parent,
26762306a36Sopenharmony_ci	[SDM845_CX_AO] = &cx_ao_w_mx_parent,
26862306a36Sopenharmony_ci	[SDM845_EBI] = &ebi,
26962306a36Sopenharmony_ci	[SDM845_GFX] = &gfx,
27062306a36Sopenharmony_ci	[SDM845_LCX] = &lcx,
27162306a36Sopenharmony_ci	[SDM845_LMX] = &lmx,
27262306a36Sopenharmony_ci	[SDM845_MSS] = &mss,
27362306a36Sopenharmony_ci	[SDM845_MX] = &mx,
27462306a36Sopenharmony_ci	[SDM845_MX_AO] = &mx_ao,
27562306a36Sopenharmony_ci};
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic const struct rpmhpd_desc sdm845_desc = {
27862306a36Sopenharmony_ci	.rpmhpds = sdm845_rpmhpds,
27962306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sdm845_rpmhpds),
28062306a36Sopenharmony_ci};
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci/* SDX55 RPMH powerdomains */
28362306a36Sopenharmony_cistatic struct rpmhpd *sdx55_rpmhpds[] = {
28462306a36Sopenharmony_ci	[SDX55_CX] = &cx_w_mx_parent,
28562306a36Sopenharmony_ci	[SDX55_MSS] = &mss,
28662306a36Sopenharmony_ci	[SDX55_MX] = &mx,
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic const struct rpmhpd_desc sdx55_desc = {
29062306a36Sopenharmony_ci	.rpmhpds = sdx55_rpmhpds,
29162306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sdx55_rpmhpds),
29262306a36Sopenharmony_ci};
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci/* SDX65 RPMH powerdomains */
29562306a36Sopenharmony_cistatic struct rpmhpd *sdx65_rpmhpds[] = {
29662306a36Sopenharmony_ci	[SDX65_CX] = &cx_w_mx_parent,
29762306a36Sopenharmony_ci	[SDX65_CX_AO] = &cx_ao_w_mx_parent,
29862306a36Sopenharmony_ci	[SDX65_MSS] = &mss,
29962306a36Sopenharmony_ci	[SDX65_MX] = &mx,
30062306a36Sopenharmony_ci	[SDX65_MX_AO] = &mx_ao,
30162306a36Sopenharmony_ci	[SDX65_MXC] = &mxc,
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic const struct rpmhpd_desc sdx65_desc = {
30562306a36Sopenharmony_ci	.rpmhpds = sdx65_rpmhpds,
30662306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sdx65_rpmhpds),
30762306a36Sopenharmony_ci};
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci/* SDX75 RPMH powerdomains */
31062306a36Sopenharmony_cistatic struct rpmhpd *sdx75_rpmhpds[] = {
31162306a36Sopenharmony_ci	[RPMHPD_CX] = &cx,
31262306a36Sopenharmony_ci	[RPMHPD_CX_AO] = &cx_ao,
31362306a36Sopenharmony_ci	[RPMHPD_MSS] = &mss,
31462306a36Sopenharmony_ci	[RPMHPD_MX] = &mx,
31562306a36Sopenharmony_ci	[RPMHPD_MX_AO] = &mx_ao,
31662306a36Sopenharmony_ci	[RPMHPD_MXC] = &mxc,
31762306a36Sopenharmony_ci};
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic const struct rpmhpd_desc sdx75_desc = {
32062306a36Sopenharmony_ci	.rpmhpds = sdx75_rpmhpds,
32162306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sdx75_rpmhpds),
32262306a36Sopenharmony_ci};
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci/* SM6350 RPMH powerdomains */
32562306a36Sopenharmony_cistatic struct rpmhpd *sm6350_rpmhpds[] = {
32662306a36Sopenharmony_ci	[SM6350_CX] = &cx_w_mx_parent,
32762306a36Sopenharmony_ci	[SM6350_GFX] = &gfx,
32862306a36Sopenharmony_ci	[SM6350_LCX] = &lcx,
32962306a36Sopenharmony_ci	[SM6350_LMX] = &lmx,
33062306a36Sopenharmony_ci	[SM6350_MSS] = &mss,
33162306a36Sopenharmony_ci	[SM6350_MX] = &mx,
33262306a36Sopenharmony_ci};
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic const struct rpmhpd_desc sm6350_desc = {
33562306a36Sopenharmony_ci	.rpmhpds = sm6350_rpmhpds,
33662306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sm6350_rpmhpds),
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci/* SM8150 RPMH powerdomains */
34062306a36Sopenharmony_cistatic struct rpmhpd *sm8150_rpmhpds[] = {
34162306a36Sopenharmony_ci	[SM8150_CX] = &cx_w_mx_parent,
34262306a36Sopenharmony_ci	[SM8150_CX_AO] = &cx_ao_w_mx_parent,
34362306a36Sopenharmony_ci	[SM8150_EBI] = &ebi,
34462306a36Sopenharmony_ci	[SM8150_GFX] = &gfx,
34562306a36Sopenharmony_ci	[SM8150_LCX] = &lcx,
34662306a36Sopenharmony_ci	[SM8150_LMX] = &lmx,
34762306a36Sopenharmony_ci	[SM8150_MMCX] = &mmcx,
34862306a36Sopenharmony_ci	[SM8150_MMCX_AO] = &mmcx_ao,
34962306a36Sopenharmony_ci	[SM8150_MSS] = &mss,
35062306a36Sopenharmony_ci	[SM8150_MX] = &mx,
35162306a36Sopenharmony_ci	[SM8150_MX_AO] = &mx_ao,
35262306a36Sopenharmony_ci};
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8150_desc = {
35562306a36Sopenharmony_ci	.rpmhpds = sm8150_rpmhpds,
35662306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sm8150_rpmhpds),
35762306a36Sopenharmony_ci};
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic struct rpmhpd *sa8155p_rpmhpds[] = {
36062306a36Sopenharmony_ci	[SA8155P_CX] = &cx_w_mx_parent,
36162306a36Sopenharmony_ci	[SA8155P_CX_AO] = &cx_ao_w_mx_parent,
36262306a36Sopenharmony_ci	[SA8155P_EBI] = &ebi,
36362306a36Sopenharmony_ci	[SA8155P_GFX] = &gfx,
36462306a36Sopenharmony_ci	[SA8155P_MSS] = &mss,
36562306a36Sopenharmony_ci	[SA8155P_MX] = &mx,
36662306a36Sopenharmony_ci	[SA8155P_MX_AO] = &mx_ao,
36762306a36Sopenharmony_ci};
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic const struct rpmhpd_desc sa8155p_desc = {
37062306a36Sopenharmony_ci	.rpmhpds = sa8155p_rpmhpds,
37162306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sa8155p_rpmhpds),
37262306a36Sopenharmony_ci};
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci/* SM8250 RPMH powerdomains */
37562306a36Sopenharmony_cistatic struct rpmhpd *sm8250_rpmhpds[] = {
37662306a36Sopenharmony_ci	[RPMHPD_CX] = &cx_w_mx_parent,
37762306a36Sopenharmony_ci	[RPMHPD_CX_AO] = &cx_ao_w_mx_parent,
37862306a36Sopenharmony_ci	[RPMHPD_EBI] = &ebi,
37962306a36Sopenharmony_ci	[RPMHPD_GFX] = &gfx,
38062306a36Sopenharmony_ci	[RPMHPD_LCX] = &lcx,
38162306a36Sopenharmony_ci	[RPMHPD_LMX] = &lmx,
38262306a36Sopenharmony_ci	[RPMHPD_MMCX] = &mmcx,
38362306a36Sopenharmony_ci	[RPMHPD_MMCX_AO] = &mmcx_ao,
38462306a36Sopenharmony_ci	[RPMHPD_MX] = &mx,
38562306a36Sopenharmony_ci	[RPMHPD_MX_AO] = &mx_ao,
38662306a36Sopenharmony_ci};
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8250_desc = {
38962306a36Sopenharmony_ci	.rpmhpds = sm8250_rpmhpds,
39062306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sm8250_rpmhpds),
39162306a36Sopenharmony_ci};
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci/* SM8350 Power domains */
39462306a36Sopenharmony_cistatic struct rpmhpd *sm8350_rpmhpds[] = {
39562306a36Sopenharmony_ci	[RPMHPD_CX] = &cx_w_mx_parent,
39662306a36Sopenharmony_ci	[RPMHPD_CX_AO] = &cx_ao_w_mx_parent,
39762306a36Sopenharmony_ci	[RPMHPD_EBI] = &ebi,
39862306a36Sopenharmony_ci	[RPMHPD_GFX] = &gfx,
39962306a36Sopenharmony_ci	[RPMHPD_LCX] = &lcx,
40062306a36Sopenharmony_ci	[RPMHPD_LMX] = &lmx,
40162306a36Sopenharmony_ci	[RPMHPD_MMCX] = &mmcx,
40262306a36Sopenharmony_ci	[RPMHPD_MMCX_AO] = &mmcx_ao,
40362306a36Sopenharmony_ci	[RPMHPD_MSS] = &mss,
40462306a36Sopenharmony_ci	[RPMHPD_MX] = &mx,
40562306a36Sopenharmony_ci	[RPMHPD_MX_AO] = &mx_ao,
40662306a36Sopenharmony_ci	[RPMHPD_MXC] = &mxc,
40762306a36Sopenharmony_ci	[RPMHPD_MXC_AO] = &mxc_ao,
40862306a36Sopenharmony_ci};
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8350_desc = {
41162306a36Sopenharmony_ci	.rpmhpds = sm8350_rpmhpds,
41262306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sm8350_rpmhpds),
41362306a36Sopenharmony_ci};
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/* SM8450 RPMH powerdomains */
41662306a36Sopenharmony_cistatic struct rpmhpd *sm8450_rpmhpds[] = {
41762306a36Sopenharmony_ci	[RPMHPD_CX] = &cx,
41862306a36Sopenharmony_ci	[RPMHPD_CX_AO] = &cx_ao,
41962306a36Sopenharmony_ci	[RPMHPD_EBI] = &ebi,
42062306a36Sopenharmony_ci	[RPMHPD_GFX] = &gfx,
42162306a36Sopenharmony_ci	[RPMHPD_LCX] = &lcx,
42262306a36Sopenharmony_ci	[RPMHPD_LMX] = &lmx,
42362306a36Sopenharmony_ci	[RPMHPD_MMCX] = &mmcx_w_cx_parent,
42462306a36Sopenharmony_ci	[RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
42562306a36Sopenharmony_ci	[RPMHPD_MSS] = &mss,
42662306a36Sopenharmony_ci	[RPMHPD_MX] = &mx,
42762306a36Sopenharmony_ci	[RPMHPD_MX_AO] = &mx_ao,
42862306a36Sopenharmony_ci	[RPMHPD_MXC] = &mxc,
42962306a36Sopenharmony_ci	[RPMHPD_MXC_AO] = &mxc_ao,
43062306a36Sopenharmony_ci};
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8450_desc = {
43362306a36Sopenharmony_ci	.rpmhpds = sm8450_rpmhpds,
43462306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sm8450_rpmhpds),
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci/* SM8550 RPMH powerdomains */
43862306a36Sopenharmony_cistatic struct rpmhpd *sm8550_rpmhpds[] = {
43962306a36Sopenharmony_ci	[RPMHPD_CX] = &cx,
44062306a36Sopenharmony_ci	[RPMHPD_CX_AO] = &cx_ao,
44162306a36Sopenharmony_ci	[RPMHPD_EBI] = &ebi,
44262306a36Sopenharmony_ci	[RPMHPD_GFX] = &gfx,
44362306a36Sopenharmony_ci	[RPMHPD_LCX] = &lcx,
44462306a36Sopenharmony_ci	[RPMHPD_LMX] = &lmx,
44562306a36Sopenharmony_ci	[RPMHPD_MMCX] = &mmcx_w_cx_parent,
44662306a36Sopenharmony_ci	[RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
44762306a36Sopenharmony_ci	[RPMHPD_MSS] = &mss,
44862306a36Sopenharmony_ci	[RPMHPD_MX] = &mx,
44962306a36Sopenharmony_ci	[RPMHPD_MX_AO] = &mx_ao,
45062306a36Sopenharmony_ci	[RPMHPD_MXC] = &mxc,
45162306a36Sopenharmony_ci	[RPMHPD_MXC_AO] = &mxc_ao,
45262306a36Sopenharmony_ci	[RPMHPD_NSP] = &nsp,
45362306a36Sopenharmony_ci};
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic const struct rpmhpd_desc sm8550_desc = {
45662306a36Sopenharmony_ci	.rpmhpds = sm8550_rpmhpds,
45762306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sm8550_rpmhpds),
45862306a36Sopenharmony_ci};
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci/* QDU1000/QRU1000 RPMH powerdomains */
46162306a36Sopenharmony_cistatic struct rpmhpd *qdu1000_rpmhpds[] = {
46262306a36Sopenharmony_ci	[QDU1000_CX] = &cx,
46362306a36Sopenharmony_ci	[QDU1000_EBI] = &ebi,
46462306a36Sopenharmony_ci	[QDU1000_MSS] = &mss,
46562306a36Sopenharmony_ci	[QDU1000_MX] = &mx,
46662306a36Sopenharmony_ci};
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic const struct rpmhpd_desc qdu1000_desc = {
46962306a36Sopenharmony_ci	.rpmhpds = qdu1000_rpmhpds,
47062306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(qdu1000_rpmhpds),
47162306a36Sopenharmony_ci};
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci/* SC7180 RPMH powerdomains */
47462306a36Sopenharmony_cistatic struct rpmhpd *sc7180_rpmhpds[] = {
47562306a36Sopenharmony_ci	[SC7180_CX] = &cx_w_mx_parent,
47662306a36Sopenharmony_ci	[SC7180_CX_AO] = &cx_ao_w_mx_parent,
47762306a36Sopenharmony_ci	[SC7180_GFX] = &gfx,
47862306a36Sopenharmony_ci	[SC7180_LCX] = &lcx,
47962306a36Sopenharmony_ci	[SC7180_LMX] = &lmx,
48062306a36Sopenharmony_ci	[SC7180_MSS] = &mss,
48162306a36Sopenharmony_ci	[SC7180_MX] = &mx,
48262306a36Sopenharmony_ci	[SC7180_MX_AO] = &mx_ao,
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic const struct rpmhpd_desc sc7180_desc = {
48662306a36Sopenharmony_ci	.rpmhpds = sc7180_rpmhpds,
48762306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sc7180_rpmhpds),
48862306a36Sopenharmony_ci};
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/* SC7280 RPMH powerdomains */
49162306a36Sopenharmony_cistatic struct rpmhpd *sc7280_rpmhpds[] = {
49262306a36Sopenharmony_ci	[SC7280_CX] = &cx,
49362306a36Sopenharmony_ci	[SC7280_CX_AO] = &cx_ao,
49462306a36Sopenharmony_ci	[SC7280_EBI] = &ebi,
49562306a36Sopenharmony_ci	[SC7280_GFX] = &gfx,
49662306a36Sopenharmony_ci	[SC7280_LCX] = &lcx,
49762306a36Sopenharmony_ci	[SC7280_LMX] = &lmx,
49862306a36Sopenharmony_ci	[SC7280_MSS] = &mss,
49962306a36Sopenharmony_ci	[SC7280_MX] = &mx,
50062306a36Sopenharmony_ci	[SC7280_MX_AO] = &mx_ao,
50162306a36Sopenharmony_ci};
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic const struct rpmhpd_desc sc7280_desc = {
50462306a36Sopenharmony_ci	.rpmhpds = sc7280_rpmhpds,
50562306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sc7280_rpmhpds),
50662306a36Sopenharmony_ci};
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/* SC8180x RPMH powerdomains */
50962306a36Sopenharmony_cistatic struct rpmhpd *sc8180x_rpmhpds[] = {
51062306a36Sopenharmony_ci	[SC8180X_CX] = &cx_w_mx_parent,
51162306a36Sopenharmony_ci	[SC8180X_CX_AO] = &cx_ao_w_mx_parent,
51262306a36Sopenharmony_ci	[SC8180X_EBI] = &ebi,
51362306a36Sopenharmony_ci	[SC8180X_GFX] = &gfx,
51462306a36Sopenharmony_ci	[SC8180X_LCX] = &lcx,
51562306a36Sopenharmony_ci	[SC8180X_LMX] = &lmx,
51662306a36Sopenharmony_ci	[SC8180X_MMCX] = &mmcx,
51762306a36Sopenharmony_ci	[SC8180X_MMCX_AO] = &mmcx_ao,
51862306a36Sopenharmony_ci	[SC8180X_MSS] = &mss,
51962306a36Sopenharmony_ci	[SC8180X_MX] = &mx,
52062306a36Sopenharmony_ci	[SC8180X_MX_AO] = &mx_ao,
52162306a36Sopenharmony_ci};
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistatic const struct rpmhpd_desc sc8180x_desc = {
52462306a36Sopenharmony_ci	.rpmhpds = sc8180x_rpmhpds,
52562306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sc8180x_rpmhpds),
52662306a36Sopenharmony_ci};
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/* SC8280xp RPMH powerdomains */
52962306a36Sopenharmony_cistatic struct rpmhpd *sc8280xp_rpmhpds[] = {
53062306a36Sopenharmony_ci	[SC8280XP_CX] = &cx,
53162306a36Sopenharmony_ci	[SC8280XP_CX_AO] = &cx_ao,
53262306a36Sopenharmony_ci	[SC8280XP_EBI] = &ebi,
53362306a36Sopenharmony_ci	[SC8280XP_GFX] = &gfx,
53462306a36Sopenharmony_ci	[SC8280XP_LCX] = &lcx,
53562306a36Sopenharmony_ci	[SC8280XP_LMX] = &lmx,
53662306a36Sopenharmony_ci	[SC8280XP_MMCX] = &mmcx,
53762306a36Sopenharmony_ci	[SC8280XP_MMCX_AO] = &mmcx_ao,
53862306a36Sopenharmony_ci	[SC8280XP_MX] = &mx,
53962306a36Sopenharmony_ci	[SC8280XP_MX_AO] = &mx_ao,
54062306a36Sopenharmony_ci	[SC8280XP_NSP] = &nsp,
54162306a36Sopenharmony_ci	[SC8280XP_QPHY] = &qphy,
54262306a36Sopenharmony_ci};
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic const struct rpmhpd_desc sc8280xp_desc = {
54562306a36Sopenharmony_ci	.rpmhpds = sc8280xp_rpmhpds,
54662306a36Sopenharmony_ci	.num_pds = ARRAY_SIZE(sc8280xp_rpmhpds),
54762306a36Sopenharmony_ci};
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic const struct of_device_id rpmhpd_match_table[] = {
55062306a36Sopenharmony_ci	{ .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
55162306a36Sopenharmony_ci	{ .compatible = "qcom,sa8155p-rpmhpd", .data = &sa8155p_desc },
55262306a36Sopenharmony_ci	{ .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc },
55362306a36Sopenharmony_ci	{ .compatible = "qcom,sa8775p-rpmhpd", .data = &sa8775p_desc },
55462306a36Sopenharmony_ci	{ .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
55562306a36Sopenharmony_ci	{ .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
55662306a36Sopenharmony_ci	{ .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
55762306a36Sopenharmony_ci	{ .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc },
55862306a36Sopenharmony_ci	{ .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc },
55962306a36Sopenharmony_ci	{ .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
56062306a36Sopenharmony_ci	{ .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
56162306a36Sopenharmony_ci	{ .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc},
56262306a36Sopenharmony_ci	{ .compatible = "qcom,sdx75-rpmhpd", .data = &sdx75_desc},
56362306a36Sopenharmony_ci	{ .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc },
56462306a36Sopenharmony_ci	{ .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc },
56562306a36Sopenharmony_ci	{ .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc },
56662306a36Sopenharmony_ci	{ .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc },
56762306a36Sopenharmony_ci	{ .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc },
56862306a36Sopenharmony_ci	{ .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc },
56962306a36Sopenharmony_ci	{ }
57062306a36Sopenharmony_ci};
57162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rpmhpd_match_table);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic int rpmhpd_send_corner(struct rpmhpd *pd, int state,
57462306a36Sopenharmony_ci			      unsigned int corner, bool sync)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	struct tcs_cmd cmd = {
57762306a36Sopenharmony_ci		.addr = pd->addr,
57862306a36Sopenharmony_ci		.data = corner,
57962306a36Sopenharmony_ci	};
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/*
58262306a36Sopenharmony_ci	 * Wait for an ack only when we are increasing the
58362306a36Sopenharmony_ci	 * perf state of the power domain
58462306a36Sopenharmony_ci	 */
58562306a36Sopenharmony_ci	if (sync)
58662306a36Sopenharmony_ci		return rpmh_write(pd->dev, state, &cmd, 1);
58762306a36Sopenharmony_ci	else
58862306a36Sopenharmony_ci		return rpmh_write_async(pd->dev, state, &cmd, 1);
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic void to_active_sleep(struct rpmhpd *pd, unsigned int corner,
59262306a36Sopenharmony_ci			    unsigned int *active, unsigned int *sleep)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	*active = corner;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (pd->active_only)
59762306a36Sopenharmony_ci		*sleep = 0;
59862306a36Sopenharmony_ci	else
59962306a36Sopenharmony_ci		*sleep = *active;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci/*
60362306a36Sopenharmony_ci * This function is used to aggregate the votes across the active only
60462306a36Sopenharmony_ci * resources and its peers. The aggregated votes are sent to RPMh as
60562306a36Sopenharmony_ci * ACTIVE_ONLY votes (which take effect immediately), as WAKE_ONLY votes
60662306a36Sopenharmony_ci * (applied by RPMh on system wakeup) and as SLEEP votes (applied by RPMh
60762306a36Sopenharmony_ci * on system sleep).
60862306a36Sopenharmony_ci * We send ACTIVE_ONLY votes for resources without any peers. For others,
60962306a36Sopenharmony_ci * which have an active only peer, all 3 votes are sent.
61062306a36Sopenharmony_ci */
61162306a36Sopenharmony_cistatic int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	int ret;
61462306a36Sopenharmony_ci	struct rpmhpd *peer = pd->peer;
61562306a36Sopenharmony_ci	unsigned int active_corner, sleep_corner;
61662306a36Sopenharmony_ci	unsigned int this_active_corner = 0, this_sleep_corner = 0;
61762306a36Sopenharmony_ci	unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
61862306a36Sopenharmony_ci	unsigned int peer_enabled_corner;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (pd->state_synced) {
62162306a36Sopenharmony_ci		to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
62262306a36Sopenharmony_ci	} else {
62362306a36Sopenharmony_ci		/* Clamp to highest corner if sync_state hasn't happened */
62462306a36Sopenharmony_ci		this_active_corner = pd->level_count - 1;
62562306a36Sopenharmony_ci		this_sleep_corner = pd->level_count - 1;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (peer && peer->enabled) {
62962306a36Sopenharmony_ci		peer_enabled_corner = max(peer->corner, peer->enable_corner);
63062306a36Sopenharmony_ci		to_active_sleep(peer, peer_enabled_corner, &peer_active_corner,
63162306a36Sopenharmony_ci				&peer_sleep_corner);
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	active_corner = max(this_active_corner, peer_active_corner);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	ret = rpmhpd_send_corner(pd, RPMH_ACTIVE_ONLY_STATE, active_corner,
63762306a36Sopenharmony_ci				 active_corner > pd->active_corner);
63862306a36Sopenharmony_ci	if (ret)
63962306a36Sopenharmony_ci		return ret;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	pd->active_corner = active_corner;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (peer) {
64462306a36Sopenharmony_ci		peer->active_corner = active_corner;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		ret = rpmhpd_send_corner(pd, RPMH_WAKE_ONLY_STATE,
64762306a36Sopenharmony_ci					 active_corner, false);
64862306a36Sopenharmony_ci		if (ret)
64962306a36Sopenharmony_ci			return ret;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		sleep_corner = max(this_sleep_corner, peer_sleep_corner);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci		return rpmhpd_send_corner(pd, RPMH_SLEEP_STATE, sleep_corner,
65462306a36Sopenharmony_ci					  false);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	return ret;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic int rpmhpd_power_on(struct generic_pm_domain *domain)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct rpmhpd *pd = domain_to_rpmhpd(domain);
66362306a36Sopenharmony_ci	unsigned int corner;
66462306a36Sopenharmony_ci	int ret;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	mutex_lock(&rpmhpd_lock);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	corner = max(pd->corner, pd->enable_corner);
66962306a36Sopenharmony_ci	ret = rpmhpd_aggregate_corner(pd, corner);
67062306a36Sopenharmony_ci	if (!ret)
67162306a36Sopenharmony_ci		pd->enabled = true;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	mutex_unlock(&rpmhpd_lock);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	return ret;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic int rpmhpd_power_off(struct generic_pm_domain *domain)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct rpmhpd *pd = domain_to_rpmhpd(domain);
68162306a36Sopenharmony_ci	int ret;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	mutex_lock(&rpmhpd_lock);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	ret = rpmhpd_aggregate_corner(pd, 0);
68662306a36Sopenharmony_ci	if (!ret)
68762306a36Sopenharmony_ci		pd->enabled = false;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	mutex_unlock(&rpmhpd_lock);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	return ret;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
69562306a36Sopenharmony_ci					unsigned int level)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct rpmhpd *pd = domain_to_rpmhpd(domain);
69862306a36Sopenharmony_ci	int ret = 0, i;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	mutex_lock(&rpmhpd_lock);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	for (i = 0; i < pd->level_count; i++)
70362306a36Sopenharmony_ci		if (level <= pd->level[i])
70462306a36Sopenharmony_ci			break;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/*
70762306a36Sopenharmony_ci	 * If the level requested is more than that supported by the
70862306a36Sopenharmony_ci	 * max corner, just set it to max anyway.
70962306a36Sopenharmony_ci	 */
71062306a36Sopenharmony_ci	if (i == pd->level_count)
71162306a36Sopenharmony_ci		i--;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (pd->enabled) {
71462306a36Sopenharmony_ci		/* Ensure that the domain isn't turn off */
71562306a36Sopenharmony_ci		if (i < pd->enable_corner)
71662306a36Sopenharmony_ci			i = pd->enable_corner;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		ret = rpmhpd_aggregate_corner(pd, i);
71962306a36Sopenharmony_ci		if (ret)
72062306a36Sopenharmony_ci			goto out;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	pd->corner = i;
72462306a36Sopenharmony_ciout:
72562306a36Sopenharmony_ci	mutex_unlock(&rpmhpd_lock);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	return ret;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic unsigned int rpmhpd_get_performance_state(struct generic_pm_domain *genpd,
73162306a36Sopenharmony_ci						 struct dev_pm_opp *opp)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	return dev_pm_opp_get_level(opp);
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	int i;
73962306a36Sopenharmony_ci	const u16 *buf;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	buf = cmd_db_read_aux_data(rpmhpd->res_name, &rpmhpd->level_count);
74262306a36Sopenharmony_ci	if (IS_ERR(buf))
74362306a36Sopenharmony_ci		return PTR_ERR(buf);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	/* 2 bytes used for each command DB aux data entry */
74662306a36Sopenharmony_ci	rpmhpd->level_count >>= 1;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (rpmhpd->level_count > RPMH_ARC_MAX_LEVELS)
74962306a36Sopenharmony_ci		return -EINVAL;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	for (i = 0; i < rpmhpd->level_count; i++) {
75262306a36Sopenharmony_ci		rpmhpd->level[i] = buf[i];
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		/* Remember the first corner with non-zero level */
75562306a36Sopenharmony_ci		if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i])
75662306a36Sopenharmony_ci			rpmhpd->enable_corner = i;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		/*
75962306a36Sopenharmony_ci		 * The AUX data may be zero padded.  These 0 valued entries at
76062306a36Sopenharmony_ci		 * the end of the map must be ignored.
76162306a36Sopenharmony_ci		 */
76262306a36Sopenharmony_ci		if (i > 0 && rpmhpd->level[i] == 0) {
76362306a36Sopenharmony_ci			rpmhpd->level_count = i;
76462306a36Sopenharmony_ci			break;
76562306a36Sopenharmony_ci		}
76662306a36Sopenharmony_ci		pr_debug("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i,
76762306a36Sopenharmony_ci			 rpmhpd->level[i]);
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	return 0;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic int rpmhpd_probe(struct platform_device *pdev)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	int i, ret;
77662306a36Sopenharmony_ci	size_t num_pds;
77762306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
77862306a36Sopenharmony_ci	struct genpd_onecell_data *data;
77962306a36Sopenharmony_ci	struct rpmhpd **rpmhpds;
78062306a36Sopenharmony_ci	const struct rpmhpd_desc *desc;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	desc = of_device_get_match_data(dev);
78362306a36Sopenharmony_ci	if (!desc)
78462306a36Sopenharmony_ci		return -EINVAL;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	rpmhpds = desc->rpmhpds;
78762306a36Sopenharmony_ci	num_pds = desc->num_pds;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
79062306a36Sopenharmony_ci	if (!data)
79162306a36Sopenharmony_ci		return -ENOMEM;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	data->domains = devm_kcalloc(dev, num_pds, sizeof(*data->domains),
79462306a36Sopenharmony_ci				     GFP_KERNEL);
79562306a36Sopenharmony_ci	if (!data->domains)
79662306a36Sopenharmony_ci		return -ENOMEM;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	data->num_domains = num_pds;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	for (i = 0; i < num_pds; i++) {
80162306a36Sopenharmony_ci		if (!rpmhpds[i])
80262306a36Sopenharmony_ci			continue;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		rpmhpds[i]->dev = dev;
80562306a36Sopenharmony_ci		rpmhpds[i]->addr = cmd_db_read_addr(rpmhpds[i]->res_name);
80662306a36Sopenharmony_ci		if (!rpmhpds[i]->addr) {
80762306a36Sopenharmony_ci			dev_err(dev, "Could not find RPMh address for resource %s\n",
80862306a36Sopenharmony_ci				rpmhpds[i]->res_name);
80962306a36Sopenharmony_ci			return -ENODEV;
81062306a36Sopenharmony_ci		}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		ret = cmd_db_read_slave_id(rpmhpds[i]->res_name);
81362306a36Sopenharmony_ci		if (ret != CMD_DB_HW_ARC) {
81462306a36Sopenharmony_ci			dev_err(dev, "RPMh slave ID mismatch\n");
81562306a36Sopenharmony_ci			return -EINVAL;
81662306a36Sopenharmony_ci		}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		ret = rpmhpd_update_level_mapping(rpmhpds[i]);
81962306a36Sopenharmony_ci		if (ret)
82062306a36Sopenharmony_ci			return ret;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		rpmhpds[i]->pd.power_off = rpmhpd_power_off;
82362306a36Sopenharmony_ci		rpmhpds[i]->pd.power_on = rpmhpd_power_on;
82462306a36Sopenharmony_ci		rpmhpds[i]->pd.set_performance_state = rpmhpd_set_performance_state;
82562306a36Sopenharmony_ci		rpmhpds[i]->pd.opp_to_performance_state = rpmhpd_get_performance_state;
82662306a36Sopenharmony_ci		pm_genpd_init(&rpmhpds[i]->pd, NULL, true);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci		data->domains[i] = &rpmhpds[i]->pd;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Add subdomains */
83262306a36Sopenharmony_ci	for (i = 0; i < num_pds; i++) {
83362306a36Sopenharmony_ci		if (!rpmhpds[i])
83462306a36Sopenharmony_ci			continue;
83562306a36Sopenharmony_ci		if (rpmhpds[i]->parent)
83662306a36Sopenharmony_ci			pm_genpd_add_subdomain(rpmhpds[i]->parent,
83762306a36Sopenharmony_ci					       &rpmhpds[i]->pd);
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic void rpmhpd_sync_state(struct device *dev)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	const struct rpmhpd_desc *desc = of_device_get_match_data(dev);
84662306a36Sopenharmony_ci	struct rpmhpd **rpmhpds = desc->rpmhpds;
84762306a36Sopenharmony_ci	unsigned int corner;
84862306a36Sopenharmony_ci	struct rpmhpd *pd;
84962306a36Sopenharmony_ci	unsigned int i;
85062306a36Sopenharmony_ci	int ret;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	mutex_lock(&rpmhpd_lock);
85362306a36Sopenharmony_ci	for (i = 0; i < desc->num_pds; i++) {
85462306a36Sopenharmony_ci		pd = rpmhpds[i];
85562306a36Sopenharmony_ci		if (!pd)
85662306a36Sopenharmony_ci			continue;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci		pd->state_synced = true;
85962306a36Sopenharmony_ci		if (pd->enabled)
86062306a36Sopenharmony_ci			corner = max(pd->corner, pd->enable_corner);
86162306a36Sopenharmony_ci		else
86262306a36Sopenharmony_ci			corner = 0;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci		ret = rpmhpd_aggregate_corner(pd, corner);
86562306a36Sopenharmony_ci		if (ret)
86662306a36Sopenharmony_ci			dev_err(dev, "failed to sync %s\n", pd->res_name);
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci	mutex_unlock(&rpmhpd_lock);
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic struct platform_driver rpmhpd_driver = {
87262306a36Sopenharmony_ci	.driver = {
87362306a36Sopenharmony_ci		.name = "qcom-rpmhpd",
87462306a36Sopenharmony_ci		.of_match_table = rpmhpd_match_table,
87562306a36Sopenharmony_ci		.suppress_bind_attrs = true,
87662306a36Sopenharmony_ci		.sync_state = rpmhpd_sync_state,
87762306a36Sopenharmony_ci	},
87862306a36Sopenharmony_ci	.probe = rpmhpd_probe,
87962306a36Sopenharmony_ci};
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_cistatic int __init rpmhpd_init(void)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	return platform_driver_register(&rpmhpd_driver);
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_cicore_initcall(rpmhpd_init);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Power Domain Driver");
88862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
889