18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Rockchip Generic power domain support.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015 ROCKCHIP, Co. Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/io.h>
98c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/pm_clock.h>
128c2ecf20Sopenharmony_ci#include <linux/pm_domain.h>
138c2ecf20Sopenharmony_ci#include <linux/of_address.h>
148c2ecf20Sopenharmony_ci#include <linux/of_clk.h>
158c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
168c2ecf20Sopenharmony_ci#include <linux/clk.h>
178c2ecf20Sopenharmony_ci#include <linux/regmap.h>
188c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
198c2ecf20Sopenharmony_ci#include <dt-bindings/power/px30-power.h>
208c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3036-power.h>
218c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3066-power.h>
228c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3128-power.h>
238c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3188-power.h>
248c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3228-power.h>
258c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3288-power.h>
268c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3328-power.h>
278c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3366-power.h>
288c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3368-power.h>
298c2ecf20Sopenharmony_ci#include <dt-bindings/power/rk3399-power.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct rockchip_domain_info {
328c2ecf20Sopenharmony_ci	int pwr_mask;
338c2ecf20Sopenharmony_ci	int status_mask;
348c2ecf20Sopenharmony_ci	int req_mask;
358c2ecf20Sopenharmony_ci	int idle_mask;
368c2ecf20Sopenharmony_ci	int ack_mask;
378c2ecf20Sopenharmony_ci	bool active_wakeup;
388c2ecf20Sopenharmony_ci	int pwr_w_mask;
398c2ecf20Sopenharmony_ci	int req_w_mask;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct rockchip_pmu_info {
438c2ecf20Sopenharmony_ci	u32 pwr_offset;
448c2ecf20Sopenharmony_ci	u32 status_offset;
458c2ecf20Sopenharmony_ci	u32 req_offset;
468c2ecf20Sopenharmony_ci	u32 idle_offset;
478c2ecf20Sopenharmony_ci	u32 ack_offset;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	u32 core_pwrcnt_offset;
508c2ecf20Sopenharmony_ci	u32 gpu_pwrcnt_offset;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	unsigned int core_power_transition_time;
538c2ecf20Sopenharmony_ci	unsigned int gpu_power_transition_time;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	int num_domains;
568c2ecf20Sopenharmony_ci	const struct rockchip_domain_info *domain_info;
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define MAX_QOS_REGS_NUM	5
608c2ecf20Sopenharmony_ci#define QOS_PRIORITY		0x08
618c2ecf20Sopenharmony_ci#define QOS_MODE		0x0c
628c2ecf20Sopenharmony_ci#define QOS_BANDWIDTH		0x10
638c2ecf20Sopenharmony_ci#define QOS_SATURATION		0x14
648c2ecf20Sopenharmony_ci#define QOS_EXTCONTROL		0x18
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistruct rockchip_pm_domain {
678c2ecf20Sopenharmony_ci	struct generic_pm_domain genpd;
688c2ecf20Sopenharmony_ci	const struct rockchip_domain_info *info;
698c2ecf20Sopenharmony_ci	struct rockchip_pmu *pmu;
708c2ecf20Sopenharmony_ci	int num_qos;
718c2ecf20Sopenharmony_ci	struct regmap **qos_regmap;
728c2ecf20Sopenharmony_ci	u32 *qos_save_regs[MAX_QOS_REGS_NUM];
738c2ecf20Sopenharmony_ci	int num_clks;
748c2ecf20Sopenharmony_ci	struct clk_bulk_data *clks;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistruct rockchip_pmu {
788c2ecf20Sopenharmony_ci	struct device *dev;
798c2ecf20Sopenharmony_ci	struct regmap *regmap;
808c2ecf20Sopenharmony_ci	const struct rockchip_pmu_info *info;
818c2ecf20Sopenharmony_ci	struct mutex mutex; /* mutex lock for pmu */
828c2ecf20Sopenharmony_ci	struct genpd_onecell_data genpd_data;
838c2ecf20Sopenharmony_ci	struct generic_pm_domain *domains[];
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define DOMAIN(pwr, status, req, idle, ack, wakeup)	\
898c2ecf20Sopenharmony_ci{							\
908c2ecf20Sopenharmony_ci	.pwr_mask = (pwr),				\
918c2ecf20Sopenharmony_ci	.status_mask = (status),			\
928c2ecf20Sopenharmony_ci	.req_mask = (req),				\
938c2ecf20Sopenharmony_ci	.idle_mask = (idle),				\
948c2ecf20Sopenharmony_ci	.ack_mask = (ack),				\
958c2ecf20Sopenharmony_ci	.active_wakeup = (wakeup),			\
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#define DOMAIN_M(pwr, status, req, idle, ack, wakeup)	\
998c2ecf20Sopenharmony_ci{							\
1008c2ecf20Sopenharmony_ci	.pwr_w_mask = (pwr) << 16,			\
1018c2ecf20Sopenharmony_ci	.pwr_mask = (pwr),				\
1028c2ecf20Sopenharmony_ci	.status_mask = (status),			\
1038c2ecf20Sopenharmony_ci	.req_w_mask = (req) << 16,			\
1048c2ecf20Sopenharmony_ci	.req_mask = (req),				\
1058c2ecf20Sopenharmony_ci	.idle_mask = (idle),				\
1068c2ecf20Sopenharmony_ci	.ack_mask = (ack),				\
1078c2ecf20Sopenharmony_ci	.active_wakeup = wakeup,			\
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci#define DOMAIN_RK3036(req, ack, idle, wakeup)		\
1118c2ecf20Sopenharmony_ci{							\
1128c2ecf20Sopenharmony_ci	.req_mask = (req),				\
1138c2ecf20Sopenharmony_ci	.req_w_mask = (req) << 16,			\
1148c2ecf20Sopenharmony_ci	.ack_mask = (ack),				\
1158c2ecf20Sopenharmony_ci	.idle_mask = (idle),				\
1168c2ecf20Sopenharmony_ci	.active_wakeup = wakeup,			\
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci#define DOMAIN_PX30(pwr, status, req, wakeup)		\
1208c2ecf20Sopenharmony_ci	DOMAIN_M(pwr, status, req, (req) << 16, req, wakeup)
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci#define DOMAIN_RK3288(pwr, status, req, wakeup)		\
1238c2ecf20Sopenharmony_ci	DOMAIN(pwr, status, req, req, (req) << 16, wakeup)
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define DOMAIN_RK3328(pwr, status, req, wakeup)		\
1268c2ecf20Sopenharmony_ci	DOMAIN_M(pwr, pwr, req, (req) << 10, req, wakeup)
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#define DOMAIN_RK3368(pwr, status, req, wakeup)		\
1298c2ecf20Sopenharmony_ci	DOMAIN(pwr, status, req, (req) << 16, req, wakeup)
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci#define DOMAIN_RK3399(pwr, status, req, wakeup)		\
1328c2ecf20Sopenharmony_ci	DOMAIN(pwr, status, req, req, req, wakeup)
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
1378c2ecf20Sopenharmony_ci	const struct rockchip_domain_info *pd_info = pd->info;
1388c2ecf20Sopenharmony_ci	unsigned int val;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	regmap_read(pmu->regmap, pmu->info->idle_offset, &val);
1418c2ecf20Sopenharmony_ci	return (val & pd_info->idle_mask) == pd_info->idle_mask;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	unsigned int val;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
1498c2ecf20Sopenharmony_ci	return val;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
1538c2ecf20Sopenharmony_ci					 bool idle)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	const struct rockchip_domain_info *pd_info = pd->info;
1568c2ecf20Sopenharmony_ci	struct generic_pm_domain *genpd = &pd->genpd;
1578c2ecf20Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
1588c2ecf20Sopenharmony_ci	unsigned int target_ack;
1598c2ecf20Sopenharmony_ci	unsigned int val;
1608c2ecf20Sopenharmony_ci	bool is_idle;
1618c2ecf20Sopenharmony_ci	int ret;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (pd_info->req_mask == 0)
1648c2ecf20Sopenharmony_ci		return 0;
1658c2ecf20Sopenharmony_ci	else if (pd_info->req_w_mask)
1668c2ecf20Sopenharmony_ci		regmap_write(pmu->regmap, pmu->info->req_offset,
1678c2ecf20Sopenharmony_ci			     idle ? (pd_info->req_mask | pd_info->req_w_mask) :
1688c2ecf20Sopenharmony_ci			     pd_info->req_w_mask);
1698c2ecf20Sopenharmony_ci	else
1708c2ecf20Sopenharmony_ci		regmap_update_bits(pmu->regmap, pmu->info->req_offset,
1718c2ecf20Sopenharmony_ci				   pd_info->req_mask, idle ? -1U : 0);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	dsb(sy);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* Wait util idle_ack = 1 */
1768c2ecf20Sopenharmony_ci	target_ack = idle ? pd_info->ack_mask : 0;
1778c2ecf20Sopenharmony_ci	ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val,
1788c2ecf20Sopenharmony_ci					(val & pd_info->ack_mask) == target_ack,
1798c2ecf20Sopenharmony_ci					0, 10000);
1808c2ecf20Sopenharmony_ci	if (ret) {
1818c2ecf20Sopenharmony_ci		dev_err(pmu->dev,
1828c2ecf20Sopenharmony_ci			"failed to get ack on domain '%s', val=0x%x\n",
1838c2ecf20Sopenharmony_ci			genpd->name, val);
1848c2ecf20Sopenharmony_ci		return ret;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd,
1888c2ecf20Sopenharmony_ci					is_idle, is_idle == idle, 0, 10000);
1898c2ecf20Sopenharmony_ci	if (ret) {
1908c2ecf20Sopenharmony_ci		dev_err(pmu->dev,
1918c2ecf20Sopenharmony_ci			"failed to set idle on domain '%s', val=%d\n",
1928c2ecf20Sopenharmony_ci			genpd->name, is_idle);
1938c2ecf20Sopenharmony_ci		return ret;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return 0;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	int i;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	for (i = 0; i < pd->num_qos; i++) {
2048c2ecf20Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
2058c2ecf20Sopenharmony_ci			    QOS_PRIORITY,
2068c2ecf20Sopenharmony_ci			    &pd->qos_save_regs[0][i]);
2078c2ecf20Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
2088c2ecf20Sopenharmony_ci			    QOS_MODE,
2098c2ecf20Sopenharmony_ci			    &pd->qos_save_regs[1][i]);
2108c2ecf20Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
2118c2ecf20Sopenharmony_ci			    QOS_BANDWIDTH,
2128c2ecf20Sopenharmony_ci			    &pd->qos_save_regs[2][i]);
2138c2ecf20Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
2148c2ecf20Sopenharmony_ci			    QOS_SATURATION,
2158c2ecf20Sopenharmony_ci			    &pd->qos_save_regs[3][i]);
2168c2ecf20Sopenharmony_ci		regmap_read(pd->qos_regmap[i],
2178c2ecf20Sopenharmony_ci			    QOS_EXTCONTROL,
2188c2ecf20Sopenharmony_ci			    &pd->qos_save_regs[4][i]);
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci	return 0;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	int i;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	for (i = 0; i < pd->num_qos; i++) {
2288c2ecf20Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
2298c2ecf20Sopenharmony_ci			     QOS_PRIORITY,
2308c2ecf20Sopenharmony_ci			     pd->qos_save_regs[0][i]);
2318c2ecf20Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
2328c2ecf20Sopenharmony_ci			     QOS_MODE,
2338c2ecf20Sopenharmony_ci			     pd->qos_save_regs[1][i]);
2348c2ecf20Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
2358c2ecf20Sopenharmony_ci			     QOS_BANDWIDTH,
2368c2ecf20Sopenharmony_ci			     pd->qos_save_regs[2][i]);
2378c2ecf20Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
2388c2ecf20Sopenharmony_ci			     QOS_SATURATION,
2398c2ecf20Sopenharmony_ci			     pd->qos_save_regs[3][i]);
2408c2ecf20Sopenharmony_ci		regmap_write(pd->qos_regmap[i],
2418c2ecf20Sopenharmony_ci			     QOS_EXTCONTROL,
2428c2ecf20Sopenharmony_ci			     pd->qos_save_regs[4][i]);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return 0;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
2518c2ecf20Sopenharmony_ci	unsigned int val;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* check idle status for idle-only domains */
2548c2ecf20Sopenharmony_ci	if (pd->info->status_mask == 0)
2558c2ecf20Sopenharmony_ci		return !rockchip_pmu_domain_is_idle(pd);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	regmap_read(pmu->regmap, pmu->info->status_offset, &val);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* 1'b0: power on, 1'b1: power off */
2608c2ecf20Sopenharmony_ci	return !(val & pd->info->status_mask);
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
2648c2ecf20Sopenharmony_ci					     bool on)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
2678c2ecf20Sopenharmony_ci	struct generic_pm_domain *genpd = &pd->genpd;
2688c2ecf20Sopenharmony_ci	bool is_on;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (pd->info->pwr_mask == 0)
2718c2ecf20Sopenharmony_ci		return;
2728c2ecf20Sopenharmony_ci	else if (pd->info->pwr_w_mask)
2738c2ecf20Sopenharmony_ci		regmap_write(pmu->regmap, pmu->info->pwr_offset,
2748c2ecf20Sopenharmony_ci			     on ? pd->info->pwr_w_mask :
2758c2ecf20Sopenharmony_ci			     (pd->info->pwr_mask | pd->info->pwr_w_mask));
2768c2ecf20Sopenharmony_ci	else
2778c2ecf20Sopenharmony_ci		regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
2788c2ecf20Sopenharmony_ci				   pd->info->pwr_mask, on ? 0 : -1U);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	dsb(sy);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
2838c2ecf20Sopenharmony_ci				      is_on == on, 0, 10000)) {
2848c2ecf20Sopenharmony_ci		dev_err(pmu->dev,
2858c2ecf20Sopenharmony_ci			"failed to set domain '%s', val=%d\n",
2868c2ecf20Sopenharmony_ci			genpd->name, is_on);
2878c2ecf20Sopenharmony_ci		return;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct rockchip_pmu *pmu = pd->pmu;
2948c2ecf20Sopenharmony_ci	int ret;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	mutex_lock(&pmu->mutex);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (rockchip_pmu_domain_is_on(pd) != power_on) {
2998c2ecf20Sopenharmony_ci		ret = clk_bulk_enable(pd->num_clks, pd->clks);
3008c2ecf20Sopenharmony_ci		if (ret < 0) {
3018c2ecf20Sopenharmony_ci			dev_err(pmu->dev, "failed to enable clocks\n");
3028c2ecf20Sopenharmony_ci			mutex_unlock(&pmu->mutex);
3038c2ecf20Sopenharmony_ci			return ret;
3048c2ecf20Sopenharmony_ci		}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		if (!power_on) {
3078c2ecf20Sopenharmony_ci			rockchip_pmu_save_qos(pd);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci			/* if powering down, idle request to NIU first */
3108c2ecf20Sopenharmony_ci			rockchip_pmu_set_idle_request(pd, true);
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci		rockchip_do_pmu_set_power_domain(pd, power_on);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		if (power_on) {
3168c2ecf20Sopenharmony_ci			/* if powering up, leave idle mode */
3178c2ecf20Sopenharmony_ci			rockchip_pmu_set_idle_request(pd, false);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci			rockchip_pmu_restore_qos(pd);
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		clk_bulk_disable(pd->num_clks, pd->clks);
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	mutex_unlock(&pmu->mutex);
3268c2ecf20Sopenharmony_ci	return 0;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int rockchip_pd_power_on(struct generic_pm_domain *domain)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	return rockchip_pd_power(pd, true);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic int rockchip_pd_power_off(struct generic_pm_domain *domain)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return rockchip_pd_power(pd, false);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
3448c2ecf20Sopenharmony_ci				  struct device *dev)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct clk *clk;
3478c2ecf20Sopenharmony_ci	int i;
3488c2ecf20Sopenharmony_ci	int error;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	error = pm_clk_create(dev);
3538c2ecf20Sopenharmony_ci	if (error) {
3548c2ecf20Sopenharmony_ci		dev_err(dev, "pm_clk_create failed %d\n", error);
3558c2ecf20Sopenharmony_ci		return error;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	i = 0;
3598c2ecf20Sopenharmony_ci	while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
3608c2ecf20Sopenharmony_ci		dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
3618c2ecf20Sopenharmony_ci		error = pm_clk_add_clk(dev, clk);
3628c2ecf20Sopenharmony_ci		if (error) {
3638c2ecf20Sopenharmony_ci			dev_err(dev, "pm_clk_add_clk failed %d\n", error);
3648c2ecf20Sopenharmony_ci			clk_put(clk);
3658c2ecf20Sopenharmony_ci			pm_clk_destroy(dev);
3668c2ecf20Sopenharmony_ci			return error;
3678c2ecf20Sopenharmony_ci		}
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return 0;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
3748c2ecf20Sopenharmony_ci				   struct device *dev)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	pm_clk_destroy(dev);
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
3828c2ecf20Sopenharmony_ci				      struct device_node *node)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	const struct rockchip_domain_info *pd_info;
3858c2ecf20Sopenharmony_ci	struct rockchip_pm_domain *pd;
3868c2ecf20Sopenharmony_ci	struct device_node *qos_node;
3878c2ecf20Sopenharmony_ci	int i, j;
3888c2ecf20Sopenharmony_ci	u32 id;
3898c2ecf20Sopenharmony_ci	int error;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	error = of_property_read_u32(node, "reg", &id);
3928c2ecf20Sopenharmony_ci	if (error) {
3938c2ecf20Sopenharmony_ci		dev_err(pmu->dev,
3948c2ecf20Sopenharmony_ci			"%pOFn: failed to retrieve domain id (reg): %d\n",
3958c2ecf20Sopenharmony_ci			node, error);
3968c2ecf20Sopenharmony_ci		return -EINVAL;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (id >= pmu->info->num_domains) {
4008c2ecf20Sopenharmony_ci		dev_err(pmu->dev, "%pOFn: invalid domain id %d\n",
4018c2ecf20Sopenharmony_ci			node, id);
4028c2ecf20Sopenharmony_ci		return -EINVAL;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	pd_info = &pmu->info->domain_info[id];
4068c2ecf20Sopenharmony_ci	if (!pd_info) {
4078c2ecf20Sopenharmony_ci		dev_err(pmu->dev, "%pOFn: undefined domain id %d\n",
4088c2ecf20Sopenharmony_ci			node, id);
4098c2ecf20Sopenharmony_ci		return -EINVAL;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
4138c2ecf20Sopenharmony_ci	if (!pd)
4148c2ecf20Sopenharmony_ci		return -ENOMEM;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	pd->info = pd_info;
4178c2ecf20Sopenharmony_ci	pd->pmu = pmu;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	pd->num_clks = of_clk_get_parent_count(node);
4208c2ecf20Sopenharmony_ci	if (pd->num_clks > 0) {
4218c2ecf20Sopenharmony_ci		pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,
4228c2ecf20Sopenharmony_ci					sizeof(*pd->clks), GFP_KERNEL);
4238c2ecf20Sopenharmony_ci		if (!pd->clks)
4248c2ecf20Sopenharmony_ci			return -ENOMEM;
4258c2ecf20Sopenharmony_ci	} else {
4268c2ecf20Sopenharmony_ci		dev_dbg(pmu->dev, "%pOFn: doesn't have clocks: %d\n",
4278c2ecf20Sopenharmony_ci			node, pd->num_clks);
4288c2ecf20Sopenharmony_ci		pd->num_clks = 0;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	for (i = 0; i < pd->num_clks; i++) {
4328c2ecf20Sopenharmony_ci		pd->clks[i].clk = of_clk_get(node, i);
4338c2ecf20Sopenharmony_ci		if (IS_ERR(pd->clks[i].clk)) {
4348c2ecf20Sopenharmony_ci			error = PTR_ERR(pd->clks[i].clk);
4358c2ecf20Sopenharmony_ci			dev_err(pmu->dev,
4368c2ecf20Sopenharmony_ci				"%pOFn: failed to get clk at index %d: %d\n",
4378c2ecf20Sopenharmony_ci				node, i, error);
4388c2ecf20Sopenharmony_ci			return error;
4398c2ecf20Sopenharmony_ci		}
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	error = clk_bulk_prepare(pd->num_clks, pd->clks);
4438c2ecf20Sopenharmony_ci	if (error)
4448c2ecf20Sopenharmony_ci		goto err_put_clocks;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
4478c2ecf20Sopenharmony_ci						 NULL);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	if (pd->num_qos > 0) {
4508c2ecf20Sopenharmony_ci		pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,
4518c2ecf20Sopenharmony_ci					      sizeof(*pd->qos_regmap),
4528c2ecf20Sopenharmony_ci					      GFP_KERNEL);
4538c2ecf20Sopenharmony_ci		if (!pd->qos_regmap) {
4548c2ecf20Sopenharmony_ci			error = -ENOMEM;
4558c2ecf20Sopenharmony_ci			goto err_unprepare_clocks;
4568c2ecf20Sopenharmony_ci		}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
4598c2ecf20Sopenharmony_ci			pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,
4608c2ecf20Sopenharmony_ci							    pd->num_qos,
4618c2ecf20Sopenharmony_ci							    sizeof(u32),
4628c2ecf20Sopenharmony_ci							    GFP_KERNEL);
4638c2ecf20Sopenharmony_ci			if (!pd->qos_save_regs[j]) {
4648c2ecf20Sopenharmony_ci				error = -ENOMEM;
4658c2ecf20Sopenharmony_ci				goto err_unprepare_clocks;
4668c2ecf20Sopenharmony_ci			}
4678c2ecf20Sopenharmony_ci		}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		for (j = 0; j < pd->num_qos; j++) {
4708c2ecf20Sopenharmony_ci			qos_node = of_parse_phandle(node, "pm_qos", j);
4718c2ecf20Sopenharmony_ci			if (!qos_node) {
4728c2ecf20Sopenharmony_ci				error = -ENODEV;
4738c2ecf20Sopenharmony_ci				goto err_unprepare_clocks;
4748c2ecf20Sopenharmony_ci			}
4758c2ecf20Sopenharmony_ci			pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
4768c2ecf20Sopenharmony_ci			if (IS_ERR(pd->qos_regmap[j])) {
4778c2ecf20Sopenharmony_ci				error = -ENODEV;
4788c2ecf20Sopenharmony_ci				of_node_put(qos_node);
4798c2ecf20Sopenharmony_ci				goto err_unprepare_clocks;
4808c2ecf20Sopenharmony_ci			}
4818c2ecf20Sopenharmony_ci			of_node_put(qos_node);
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	error = rockchip_pd_power(pd, true);
4868c2ecf20Sopenharmony_ci	if (error) {
4878c2ecf20Sopenharmony_ci		dev_err(pmu->dev,
4888c2ecf20Sopenharmony_ci			"failed to power on domain '%pOFn': %d\n",
4898c2ecf20Sopenharmony_ci			node, error);
4908c2ecf20Sopenharmony_ci		goto err_unprepare_clocks;
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	pd->genpd.name = node->name;
4948c2ecf20Sopenharmony_ci	pd->genpd.power_off = rockchip_pd_power_off;
4958c2ecf20Sopenharmony_ci	pd->genpd.power_on = rockchip_pd_power_on;
4968c2ecf20Sopenharmony_ci	pd->genpd.attach_dev = rockchip_pd_attach_dev;
4978c2ecf20Sopenharmony_ci	pd->genpd.detach_dev = rockchip_pd_detach_dev;
4988c2ecf20Sopenharmony_ci	pd->genpd.flags = GENPD_FLAG_PM_CLK;
4998c2ecf20Sopenharmony_ci	if (pd_info->active_wakeup)
5008c2ecf20Sopenharmony_ci		pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
5018c2ecf20Sopenharmony_ci	pm_genpd_init(&pd->genpd, NULL, false);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	pmu->genpd_data.domains[id] = &pd->genpd;
5048c2ecf20Sopenharmony_ci	return 0;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cierr_unprepare_clocks:
5078c2ecf20Sopenharmony_ci	clk_bulk_unprepare(pd->num_clks, pd->clks);
5088c2ecf20Sopenharmony_cierr_put_clocks:
5098c2ecf20Sopenharmony_ci	clk_bulk_put(pd->num_clks, pd->clks);
5108c2ecf20Sopenharmony_ci	return error;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	int ret;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/*
5188c2ecf20Sopenharmony_ci	 * We're in the error cleanup already, so we only complain,
5198c2ecf20Sopenharmony_ci	 * but won't emit another error on top of the original one.
5208c2ecf20Sopenharmony_ci	 */
5218c2ecf20Sopenharmony_ci	ret = pm_genpd_remove(&pd->genpd);
5228c2ecf20Sopenharmony_ci	if (ret < 0)
5238c2ecf20Sopenharmony_ci		dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",
5248c2ecf20Sopenharmony_ci			pd->genpd.name, ret);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	clk_bulk_unprepare(pd->num_clks, pd->clks);
5278c2ecf20Sopenharmony_ci	clk_bulk_put(pd->num_clks, pd->clks);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* protect the zeroing of pm->num_clks */
5308c2ecf20Sopenharmony_ci	mutex_lock(&pd->pmu->mutex);
5318c2ecf20Sopenharmony_ci	pd->num_clks = 0;
5328c2ecf20Sopenharmony_ci	mutex_unlock(&pd->pmu->mutex);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/* devm will free our memory */
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct generic_pm_domain *genpd;
5408c2ecf20Sopenharmony_ci	struct rockchip_pm_domain *pd;
5418c2ecf20Sopenharmony_ci	int i;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	for (i = 0; i < pmu->genpd_data.num_domains; i++) {
5448c2ecf20Sopenharmony_ci		genpd = pmu->genpd_data.domains[i];
5458c2ecf20Sopenharmony_ci		if (genpd) {
5468c2ecf20Sopenharmony_ci			pd = to_rockchip_pd(genpd);
5478c2ecf20Sopenharmony_ci			rockchip_pm_remove_one_domain(pd);
5488c2ecf20Sopenharmony_ci		}
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/* devm will free our memory */
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_cistatic void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
5558c2ecf20Sopenharmony_ci				      u32 domain_reg_offset,
5568c2ecf20Sopenharmony_ci				      unsigned int count)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	/* First configure domain power down transition count ... */
5598c2ecf20Sopenharmony_ci	regmap_write(pmu->regmap, domain_reg_offset, count);
5608c2ecf20Sopenharmony_ci	/* ... and then power up count. */
5618c2ecf20Sopenharmony_ci	regmap_write(pmu->regmap, domain_reg_offset + 4, count);
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
5658c2ecf20Sopenharmony_ci				     struct device_node *parent)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct device_node *np;
5688c2ecf20Sopenharmony_ci	struct generic_pm_domain *child_domain, *parent_domain;
5698c2ecf20Sopenharmony_ci	int error;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	for_each_child_of_node(parent, np) {
5728c2ecf20Sopenharmony_ci		u32 idx;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		error = of_property_read_u32(parent, "reg", &idx);
5758c2ecf20Sopenharmony_ci		if (error) {
5768c2ecf20Sopenharmony_ci			dev_err(pmu->dev,
5778c2ecf20Sopenharmony_ci				"%pOFn: failed to retrieve domain id (reg): %d\n",
5788c2ecf20Sopenharmony_ci				parent, error);
5798c2ecf20Sopenharmony_ci			goto err_out;
5808c2ecf20Sopenharmony_ci		}
5818c2ecf20Sopenharmony_ci		parent_domain = pmu->genpd_data.domains[idx];
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		error = rockchip_pm_add_one_domain(pmu, np);
5848c2ecf20Sopenharmony_ci		if (error) {
5858c2ecf20Sopenharmony_ci			dev_err(pmu->dev, "failed to handle node %pOFn: %d\n",
5868c2ecf20Sopenharmony_ci				np, error);
5878c2ecf20Sopenharmony_ci			goto err_out;
5888c2ecf20Sopenharmony_ci		}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		error = of_property_read_u32(np, "reg", &idx);
5918c2ecf20Sopenharmony_ci		if (error) {
5928c2ecf20Sopenharmony_ci			dev_err(pmu->dev,
5938c2ecf20Sopenharmony_ci				"%pOFn: failed to retrieve domain id (reg): %d\n",
5948c2ecf20Sopenharmony_ci				np, error);
5958c2ecf20Sopenharmony_ci			goto err_out;
5968c2ecf20Sopenharmony_ci		}
5978c2ecf20Sopenharmony_ci		child_domain = pmu->genpd_data.domains[idx];
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci		error = pm_genpd_add_subdomain(parent_domain, child_domain);
6008c2ecf20Sopenharmony_ci		if (error) {
6018c2ecf20Sopenharmony_ci			dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n",
6028c2ecf20Sopenharmony_ci				parent_domain->name, child_domain->name, error);
6038c2ecf20Sopenharmony_ci			goto err_out;
6048c2ecf20Sopenharmony_ci		} else {
6058c2ecf20Sopenharmony_ci			dev_dbg(pmu->dev, "%s add subdomain: %s\n",
6068c2ecf20Sopenharmony_ci				parent_domain->name, child_domain->name);
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		rockchip_pm_add_subdomain(pmu, np);
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	return 0;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cierr_out:
6158c2ecf20Sopenharmony_ci	of_node_put(np);
6168c2ecf20Sopenharmony_ci	return error;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic int rockchip_pm_domain_probe(struct platform_device *pdev)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
6228c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
6238c2ecf20Sopenharmony_ci	struct device_node *node;
6248c2ecf20Sopenharmony_ci	struct device *parent;
6258c2ecf20Sopenharmony_ci	struct rockchip_pmu *pmu;
6268c2ecf20Sopenharmony_ci	const struct of_device_id *match;
6278c2ecf20Sopenharmony_ci	const struct rockchip_pmu_info *pmu_info;
6288c2ecf20Sopenharmony_ci	int error;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	if (!np) {
6318c2ecf20Sopenharmony_ci		dev_err(dev, "device tree node not found\n");
6328c2ecf20Sopenharmony_ci		return -ENODEV;
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	match = of_match_device(dev->driver->of_match_table, dev);
6368c2ecf20Sopenharmony_ci	if (!match || !match->data) {
6378c2ecf20Sopenharmony_ci		dev_err(dev, "missing pmu data\n");
6388c2ecf20Sopenharmony_ci		return -EINVAL;
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	pmu_info = match->data;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	pmu = devm_kzalloc(dev,
6448c2ecf20Sopenharmony_ci			   struct_size(pmu, domains, pmu_info->num_domains),
6458c2ecf20Sopenharmony_ci			   GFP_KERNEL);
6468c2ecf20Sopenharmony_ci	if (!pmu)
6478c2ecf20Sopenharmony_ci		return -ENOMEM;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	pmu->dev = &pdev->dev;
6508c2ecf20Sopenharmony_ci	mutex_init(&pmu->mutex);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	pmu->info = pmu_info;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	pmu->genpd_data.domains = pmu->domains;
6558c2ecf20Sopenharmony_ci	pmu->genpd_data.num_domains = pmu_info->num_domains;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	parent = dev->parent;
6588c2ecf20Sopenharmony_ci	if (!parent) {
6598c2ecf20Sopenharmony_ci		dev_err(dev, "no parent for syscon devices\n");
6608c2ecf20Sopenharmony_ci		return -ENODEV;
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	pmu->regmap = syscon_node_to_regmap(parent->of_node);
6648c2ecf20Sopenharmony_ci	if (IS_ERR(pmu->regmap)) {
6658c2ecf20Sopenharmony_ci		dev_err(dev, "no regmap available\n");
6668c2ecf20Sopenharmony_ci		return PTR_ERR(pmu->regmap);
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	/*
6708c2ecf20Sopenharmony_ci	 * Configure power up and down transition delays for CORE
6718c2ecf20Sopenharmony_ci	 * and GPU domains.
6728c2ecf20Sopenharmony_ci	 */
6738c2ecf20Sopenharmony_ci	if (pmu_info->core_power_transition_time)
6748c2ecf20Sopenharmony_ci		rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
6758c2ecf20Sopenharmony_ci					pmu_info->core_power_transition_time);
6768c2ecf20Sopenharmony_ci	if (pmu_info->gpu_pwrcnt_offset)
6778c2ecf20Sopenharmony_ci		rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
6788c2ecf20Sopenharmony_ci					pmu_info->gpu_power_transition_time);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	error = -ENODEV;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	for_each_available_child_of_node(np, node) {
6838c2ecf20Sopenharmony_ci		error = rockchip_pm_add_one_domain(pmu, node);
6848c2ecf20Sopenharmony_ci		if (error) {
6858c2ecf20Sopenharmony_ci			dev_err(dev, "failed to handle node %pOFn: %d\n",
6868c2ecf20Sopenharmony_ci				node, error);
6878c2ecf20Sopenharmony_ci			of_node_put(node);
6888c2ecf20Sopenharmony_ci			goto err_out;
6898c2ecf20Sopenharmony_ci		}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci		error = rockchip_pm_add_subdomain(pmu, node);
6928c2ecf20Sopenharmony_ci		if (error < 0) {
6938c2ecf20Sopenharmony_ci			dev_err(dev, "failed to handle subdomain node %pOFn: %d\n",
6948c2ecf20Sopenharmony_ci				node, error);
6958c2ecf20Sopenharmony_ci			of_node_put(node);
6968c2ecf20Sopenharmony_ci			goto err_out;
6978c2ecf20Sopenharmony_ci		}
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (error) {
7018c2ecf20Sopenharmony_ci		dev_dbg(dev, "no power domains defined\n");
7028c2ecf20Sopenharmony_ci		goto err_out;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	error = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
7068c2ecf20Sopenharmony_ci	if (error) {
7078c2ecf20Sopenharmony_ci		dev_err(dev, "failed to add provider: %d\n", error);
7088c2ecf20Sopenharmony_ci		goto err_out;
7098c2ecf20Sopenharmony_ci	}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	return 0;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cierr_out:
7148c2ecf20Sopenharmony_ci	rockchip_pm_domain_cleanup(pmu);
7158c2ecf20Sopenharmony_ci	return error;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info px30_pm_domains[] = {
7198c2ecf20Sopenharmony_ci	[PX30_PD_USB]		= DOMAIN_PX30(BIT(5),  BIT(5),  BIT(10), false),
7208c2ecf20Sopenharmony_ci	[PX30_PD_SDCARD]	= DOMAIN_PX30(BIT(8),  BIT(8),  BIT(9),  false),
7218c2ecf20Sopenharmony_ci	[PX30_PD_GMAC]		= DOMAIN_PX30(BIT(10), BIT(10), BIT(6),  false),
7228c2ecf20Sopenharmony_ci	[PX30_PD_MMC_NAND]	= DOMAIN_PX30(BIT(11), BIT(11), BIT(5),  false),
7238c2ecf20Sopenharmony_ci	[PX30_PD_VPU]		= DOMAIN_PX30(BIT(12), BIT(12), BIT(14), false),
7248c2ecf20Sopenharmony_ci	[PX30_PD_VO]		= DOMAIN_PX30(BIT(13), BIT(13), BIT(7),  false),
7258c2ecf20Sopenharmony_ci	[PX30_PD_VI]		= DOMAIN_PX30(BIT(14), BIT(14), BIT(8),  false),
7268c2ecf20Sopenharmony_ci	[PX30_PD_GPU]		= DOMAIN_PX30(BIT(15), BIT(15), BIT(2),  false),
7278c2ecf20Sopenharmony_ci};
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3036_pm_domains[] = {
7308c2ecf20Sopenharmony_ci	[RK3036_PD_MSCH]	= DOMAIN_RK3036(BIT(14), BIT(23), BIT(30), true),
7318c2ecf20Sopenharmony_ci	[RK3036_PD_CORE]	= DOMAIN_RK3036(BIT(13), BIT(17), BIT(24), false),
7328c2ecf20Sopenharmony_ci	[RK3036_PD_PERI]	= DOMAIN_RK3036(BIT(12), BIT(18), BIT(25), false),
7338c2ecf20Sopenharmony_ci	[RK3036_PD_VIO]		= DOMAIN_RK3036(BIT(11), BIT(19), BIT(26), false),
7348c2ecf20Sopenharmony_ci	[RK3036_PD_VPU]		= DOMAIN_RK3036(BIT(10), BIT(20), BIT(27), false),
7358c2ecf20Sopenharmony_ci	[RK3036_PD_GPU]		= DOMAIN_RK3036(BIT(9),  BIT(21), BIT(28), false),
7368c2ecf20Sopenharmony_ci	[RK3036_PD_SYS]		= DOMAIN_RK3036(BIT(8),  BIT(22), BIT(29), false),
7378c2ecf20Sopenharmony_ci};
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3066_pm_domains[] = {
7408c2ecf20Sopenharmony_ci	[RK3066_PD_GPU]		= DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
7418c2ecf20Sopenharmony_ci	[RK3066_PD_VIDEO]	= DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
7428c2ecf20Sopenharmony_ci	[RK3066_PD_VIO]		= DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
7438c2ecf20Sopenharmony_ci	[RK3066_PD_PERI]	= DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
7448c2ecf20Sopenharmony_ci	[RK3066_PD_CPU]		= DOMAIN(0,      BIT(5), BIT(1), BIT(26), BIT(31), false),
7458c2ecf20Sopenharmony_ci};
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3128_pm_domains[] = {
7488c2ecf20Sopenharmony_ci	[RK3128_PD_CORE]	= DOMAIN_RK3288(BIT(0), BIT(0), BIT(4), false),
7498c2ecf20Sopenharmony_ci	[RK3128_PD_MSCH]	= DOMAIN_RK3288(0,      0,      BIT(6), true),
7508c2ecf20Sopenharmony_ci	[RK3128_PD_VIO]		= DOMAIN_RK3288(BIT(3), BIT(3), BIT(2), false),
7518c2ecf20Sopenharmony_ci	[RK3128_PD_VIDEO]	= DOMAIN_RK3288(BIT(2), BIT(2), BIT(1), false),
7528c2ecf20Sopenharmony_ci	[RK3128_PD_GPU]		= DOMAIN_RK3288(BIT(1), BIT(1), BIT(3), false),
7538c2ecf20Sopenharmony_ci};
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3188_pm_domains[] = {
7568c2ecf20Sopenharmony_ci	[RK3188_PD_GPU]		= DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
7578c2ecf20Sopenharmony_ci	[RK3188_PD_VIDEO]	= DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
7588c2ecf20Sopenharmony_ci	[RK3188_PD_VIO]		= DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
7598c2ecf20Sopenharmony_ci	[RK3188_PD_PERI]	= DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
7608c2ecf20Sopenharmony_ci	[RK3188_PD_CPU]		= DOMAIN(BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false),
7618c2ecf20Sopenharmony_ci};
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3228_pm_domains[] = {
7648c2ecf20Sopenharmony_ci	[RK3228_PD_CORE]	= DOMAIN_RK3036(BIT(0),  BIT(0),  BIT(16), true),
7658c2ecf20Sopenharmony_ci	[RK3228_PD_MSCH]	= DOMAIN_RK3036(BIT(1),  BIT(1),  BIT(17), true),
7668c2ecf20Sopenharmony_ci	[RK3228_PD_BUS]		= DOMAIN_RK3036(BIT(2),  BIT(2),  BIT(18), true),
7678c2ecf20Sopenharmony_ci	[RK3228_PD_SYS]		= DOMAIN_RK3036(BIT(3),  BIT(3),  BIT(19), true),
7688c2ecf20Sopenharmony_ci	[RK3228_PD_VIO]		= DOMAIN_RK3036(BIT(4),  BIT(4),  BIT(20), false),
7698c2ecf20Sopenharmony_ci	[RK3228_PD_VOP]		= DOMAIN_RK3036(BIT(5),  BIT(5),  BIT(21), false),
7708c2ecf20Sopenharmony_ci	[RK3228_PD_VPU]		= DOMAIN_RK3036(BIT(6),  BIT(6),  BIT(22), false),
7718c2ecf20Sopenharmony_ci	[RK3228_PD_RKVDEC]	= DOMAIN_RK3036(BIT(7),  BIT(7),  BIT(23), false),
7728c2ecf20Sopenharmony_ci	[RK3228_PD_GPU]		= DOMAIN_RK3036(BIT(8),  BIT(8),  BIT(24), false),
7738c2ecf20Sopenharmony_ci	[RK3228_PD_PERI]	= DOMAIN_RK3036(BIT(9),  BIT(9),  BIT(25), true),
7748c2ecf20Sopenharmony_ci	[RK3228_PD_GMAC]	= DOMAIN_RK3036(BIT(10), BIT(10), BIT(26), false),
7758c2ecf20Sopenharmony_ci};
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3288_pm_domains[] = {
7788c2ecf20Sopenharmony_ci	[RK3288_PD_VIO]		= DOMAIN_RK3288(BIT(7),  BIT(7),  BIT(4), false),
7798c2ecf20Sopenharmony_ci	[RK3288_PD_HEVC]	= DOMAIN_RK3288(BIT(14), BIT(10), BIT(9), false),
7808c2ecf20Sopenharmony_ci	[RK3288_PD_VIDEO]	= DOMAIN_RK3288(BIT(8),  BIT(8),  BIT(3), false),
7818c2ecf20Sopenharmony_ci	[RK3288_PD_GPU]		= DOMAIN_RK3288(BIT(9),  BIT(9),  BIT(2), false),
7828c2ecf20Sopenharmony_ci};
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3328_pm_domains[] = {
7858c2ecf20Sopenharmony_ci	[RK3328_PD_CORE]	= DOMAIN_RK3328(0, BIT(0), BIT(0), false),
7868c2ecf20Sopenharmony_ci	[RK3328_PD_GPU]		= DOMAIN_RK3328(0, BIT(1), BIT(1), false),
7878c2ecf20Sopenharmony_ci	[RK3328_PD_BUS]		= DOMAIN_RK3328(0, BIT(2), BIT(2), true),
7888c2ecf20Sopenharmony_ci	[RK3328_PD_MSCH]	= DOMAIN_RK3328(0, BIT(3), BIT(3), true),
7898c2ecf20Sopenharmony_ci	[RK3328_PD_PERI]	= DOMAIN_RK3328(0, BIT(4), BIT(4), true),
7908c2ecf20Sopenharmony_ci	[RK3328_PD_VIDEO]	= DOMAIN_RK3328(0, BIT(5), BIT(5), false),
7918c2ecf20Sopenharmony_ci	[RK3328_PD_HEVC]	= DOMAIN_RK3328(0, BIT(6), BIT(6), false),
7928c2ecf20Sopenharmony_ci	[RK3328_PD_VIO]		= DOMAIN_RK3328(0, BIT(8), BIT(8), false),
7938c2ecf20Sopenharmony_ci	[RK3328_PD_VPU]		= DOMAIN_RK3328(0, BIT(9), BIT(9), false),
7948c2ecf20Sopenharmony_ci};
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3366_pm_domains[] = {
7978c2ecf20Sopenharmony_ci	[RK3366_PD_PERI]	= DOMAIN_RK3368(BIT(10), BIT(10), BIT(6), true),
7988c2ecf20Sopenharmony_ci	[RK3366_PD_VIO]		= DOMAIN_RK3368(BIT(14), BIT(14), BIT(8), false),
7998c2ecf20Sopenharmony_ci	[RK3366_PD_VIDEO]	= DOMAIN_RK3368(BIT(13), BIT(13), BIT(7), false),
8008c2ecf20Sopenharmony_ci	[RK3366_PD_RKVDEC]	= DOMAIN_RK3368(BIT(11), BIT(11), BIT(7), false),
8018c2ecf20Sopenharmony_ci	[RK3366_PD_WIFIBT]	= DOMAIN_RK3368(BIT(8),  BIT(8),  BIT(9), false),
8028c2ecf20Sopenharmony_ci	[RK3366_PD_VPU]		= DOMAIN_RK3368(BIT(12), BIT(12), BIT(7), false),
8038c2ecf20Sopenharmony_ci	[RK3366_PD_GPU]		= DOMAIN_RK3368(BIT(15), BIT(15), BIT(2), false),
8048c2ecf20Sopenharmony_ci};
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3368_pm_domains[] = {
8078c2ecf20Sopenharmony_ci	[RK3368_PD_PERI]	= DOMAIN_RK3368(BIT(13), BIT(12), BIT(6), true),
8088c2ecf20Sopenharmony_ci	[RK3368_PD_VIO]		= DOMAIN_RK3368(BIT(15), BIT(14), BIT(8), false),
8098c2ecf20Sopenharmony_ci	[RK3368_PD_VIDEO]	= DOMAIN_RK3368(BIT(14), BIT(13), BIT(7), false),
8108c2ecf20Sopenharmony_ci	[RK3368_PD_GPU_0]	= DOMAIN_RK3368(BIT(16), BIT(15), BIT(2), false),
8118c2ecf20Sopenharmony_ci	[RK3368_PD_GPU_1]	= DOMAIN_RK3368(BIT(17), BIT(16), BIT(2), false),
8128c2ecf20Sopenharmony_ci};
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_cistatic const struct rockchip_domain_info rk3399_pm_domains[] = {
8158c2ecf20Sopenharmony_ci	[RK3399_PD_TCPD0]	= DOMAIN_RK3399(BIT(8),  BIT(8),  0,	   false),
8168c2ecf20Sopenharmony_ci	[RK3399_PD_TCPD1]	= DOMAIN_RK3399(BIT(9),  BIT(9),  0,	   false),
8178c2ecf20Sopenharmony_ci	[RK3399_PD_CCI]		= DOMAIN_RK3399(BIT(10), BIT(10), 0,	   true),
8188c2ecf20Sopenharmony_ci	[RK3399_PD_CCI0]	= DOMAIN_RK3399(0,	 0,	  BIT(15), true),
8198c2ecf20Sopenharmony_ci	[RK3399_PD_CCI1]	= DOMAIN_RK3399(0,	 0,	  BIT(16), true),
8208c2ecf20Sopenharmony_ci	[RK3399_PD_PERILP]	= DOMAIN_RK3399(BIT(11), BIT(11), BIT(1),  true),
8218c2ecf20Sopenharmony_ci	[RK3399_PD_PERIHP]	= DOMAIN_RK3399(BIT(12), BIT(12), BIT(2),  true),
8228c2ecf20Sopenharmony_ci	[RK3399_PD_CENTER]	= DOMAIN_RK3399(BIT(13), BIT(13), BIT(14), true),
8238c2ecf20Sopenharmony_ci	[RK3399_PD_VIO]		= DOMAIN_RK3399(BIT(14), BIT(14), BIT(17), false),
8248c2ecf20Sopenharmony_ci	[RK3399_PD_GPU]		= DOMAIN_RK3399(BIT(15), BIT(15), BIT(0),  false),
8258c2ecf20Sopenharmony_ci	[RK3399_PD_VCODEC]	= DOMAIN_RK3399(BIT(16), BIT(16), BIT(3),  false),
8268c2ecf20Sopenharmony_ci	[RK3399_PD_VDU]		= DOMAIN_RK3399(BIT(17), BIT(17), BIT(4),  false),
8278c2ecf20Sopenharmony_ci	[RK3399_PD_RGA]		= DOMAIN_RK3399(BIT(18), BIT(18), BIT(5),  false),
8288c2ecf20Sopenharmony_ci	[RK3399_PD_IEP]		= DOMAIN_RK3399(BIT(19), BIT(19), BIT(6),  false),
8298c2ecf20Sopenharmony_ci	[RK3399_PD_VO]		= DOMAIN_RK3399(BIT(20), BIT(20), 0,	   false),
8308c2ecf20Sopenharmony_ci	[RK3399_PD_VOPB]	= DOMAIN_RK3399(0,	 0,	  BIT(7),  false),
8318c2ecf20Sopenharmony_ci	[RK3399_PD_VOPL]	= DOMAIN_RK3399(0, 	 0,	  BIT(8),  false),
8328c2ecf20Sopenharmony_ci	[RK3399_PD_ISP0]	= DOMAIN_RK3399(BIT(22), BIT(22), BIT(9),  false),
8338c2ecf20Sopenharmony_ci	[RK3399_PD_ISP1]	= DOMAIN_RK3399(BIT(23), BIT(23), BIT(10), false),
8348c2ecf20Sopenharmony_ci	[RK3399_PD_HDCP]	= DOMAIN_RK3399(BIT(24), BIT(24), BIT(11), false),
8358c2ecf20Sopenharmony_ci	[RK3399_PD_GMAC]	= DOMAIN_RK3399(BIT(25), BIT(25), BIT(23), true),
8368c2ecf20Sopenharmony_ci	[RK3399_PD_EMMC]	= DOMAIN_RK3399(BIT(26), BIT(26), BIT(24), true),
8378c2ecf20Sopenharmony_ci	[RK3399_PD_USB3]	= DOMAIN_RK3399(BIT(27), BIT(27), BIT(12), true),
8388c2ecf20Sopenharmony_ci	[RK3399_PD_EDP]		= DOMAIN_RK3399(BIT(28), BIT(28), BIT(22), false),
8398c2ecf20Sopenharmony_ci	[RK3399_PD_GIC]		= DOMAIN_RK3399(BIT(29), BIT(29), BIT(27), true),
8408c2ecf20Sopenharmony_ci	[RK3399_PD_SD]		= DOMAIN_RK3399(BIT(30), BIT(30), BIT(28), true),
8418c2ecf20Sopenharmony_ci	[RK3399_PD_SDIOAUDIO]	= DOMAIN_RK3399(BIT(31), BIT(31), BIT(29), true),
8428c2ecf20Sopenharmony_ci};
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info px30_pmu = {
8458c2ecf20Sopenharmony_ci	.pwr_offset = 0x18,
8468c2ecf20Sopenharmony_ci	.status_offset = 0x20,
8478c2ecf20Sopenharmony_ci	.req_offset = 0x64,
8488c2ecf20Sopenharmony_ci	.idle_offset = 0x6c,
8498c2ecf20Sopenharmony_ci	.ack_offset = 0x6c,
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(px30_pm_domains),
8528c2ecf20Sopenharmony_ci	.domain_info = px30_pm_domains,
8538c2ecf20Sopenharmony_ci};
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3036_pmu = {
8568c2ecf20Sopenharmony_ci	.req_offset = 0x148,
8578c2ecf20Sopenharmony_ci	.idle_offset = 0x14c,
8588c2ecf20Sopenharmony_ci	.ack_offset = 0x14c,
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3036_pm_domains),
8618c2ecf20Sopenharmony_ci	.domain_info = rk3036_pm_domains,
8628c2ecf20Sopenharmony_ci};
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3066_pmu = {
8658c2ecf20Sopenharmony_ci	.pwr_offset = 0x08,
8668c2ecf20Sopenharmony_ci	.status_offset = 0x0c,
8678c2ecf20Sopenharmony_ci	.req_offset = 0x38, /* PMU_MISC_CON1 */
8688c2ecf20Sopenharmony_ci	.idle_offset = 0x0c,
8698c2ecf20Sopenharmony_ci	.ack_offset = 0x0c,
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3066_pm_domains),
8728c2ecf20Sopenharmony_ci	.domain_info = rk3066_pm_domains,
8738c2ecf20Sopenharmony_ci};
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3128_pmu = {
8768c2ecf20Sopenharmony_ci	.pwr_offset = 0x04,
8778c2ecf20Sopenharmony_ci	.status_offset = 0x08,
8788c2ecf20Sopenharmony_ci	.req_offset = 0x0c,
8798c2ecf20Sopenharmony_ci	.idle_offset = 0x10,
8808c2ecf20Sopenharmony_ci	.ack_offset = 0x10,
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3128_pm_domains),
8838c2ecf20Sopenharmony_ci	.domain_info = rk3128_pm_domains,
8848c2ecf20Sopenharmony_ci};
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3188_pmu = {
8878c2ecf20Sopenharmony_ci	.pwr_offset = 0x08,
8888c2ecf20Sopenharmony_ci	.status_offset = 0x0c,
8898c2ecf20Sopenharmony_ci	.req_offset = 0x38, /* PMU_MISC_CON1 */
8908c2ecf20Sopenharmony_ci	.idle_offset = 0x0c,
8918c2ecf20Sopenharmony_ci	.ack_offset = 0x0c,
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3188_pm_domains),
8948c2ecf20Sopenharmony_ci	.domain_info = rk3188_pm_domains,
8958c2ecf20Sopenharmony_ci};
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3228_pmu = {
8988c2ecf20Sopenharmony_ci	.req_offset = 0x40c,
8998c2ecf20Sopenharmony_ci	.idle_offset = 0x488,
9008c2ecf20Sopenharmony_ci	.ack_offset = 0x488,
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3228_pm_domains),
9038c2ecf20Sopenharmony_ci	.domain_info = rk3228_pm_domains,
9048c2ecf20Sopenharmony_ci};
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3288_pmu = {
9078c2ecf20Sopenharmony_ci	.pwr_offset = 0x08,
9088c2ecf20Sopenharmony_ci	.status_offset = 0x0c,
9098c2ecf20Sopenharmony_ci	.req_offset = 0x10,
9108c2ecf20Sopenharmony_ci	.idle_offset = 0x14,
9118c2ecf20Sopenharmony_ci	.ack_offset = 0x14,
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	.core_pwrcnt_offset = 0x34,
9148c2ecf20Sopenharmony_ci	.gpu_pwrcnt_offset = 0x3c,
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	.core_power_transition_time = 24, /* 1us */
9178c2ecf20Sopenharmony_ci	.gpu_power_transition_time = 24, /* 1us */
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3288_pm_domains),
9208c2ecf20Sopenharmony_ci	.domain_info = rk3288_pm_domains,
9218c2ecf20Sopenharmony_ci};
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3328_pmu = {
9248c2ecf20Sopenharmony_ci	.req_offset = 0x414,
9258c2ecf20Sopenharmony_ci	.idle_offset = 0x484,
9268c2ecf20Sopenharmony_ci	.ack_offset = 0x484,
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3328_pm_domains),
9298c2ecf20Sopenharmony_ci	.domain_info = rk3328_pm_domains,
9308c2ecf20Sopenharmony_ci};
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3366_pmu = {
9338c2ecf20Sopenharmony_ci	.pwr_offset = 0x0c,
9348c2ecf20Sopenharmony_ci	.status_offset = 0x10,
9358c2ecf20Sopenharmony_ci	.req_offset = 0x3c,
9368c2ecf20Sopenharmony_ci	.idle_offset = 0x40,
9378c2ecf20Sopenharmony_ci	.ack_offset = 0x40,
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	.core_pwrcnt_offset = 0x48,
9408c2ecf20Sopenharmony_ci	.gpu_pwrcnt_offset = 0x50,
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	.core_power_transition_time = 24,
9438c2ecf20Sopenharmony_ci	.gpu_power_transition_time = 24,
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3366_pm_domains),
9468c2ecf20Sopenharmony_ci	.domain_info = rk3366_pm_domains,
9478c2ecf20Sopenharmony_ci};
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3368_pmu = {
9508c2ecf20Sopenharmony_ci	.pwr_offset = 0x0c,
9518c2ecf20Sopenharmony_ci	.status_offset = 0x10,
9528c2ecf20Sopenharmony_ci	.req_offset = 0x3c,
9538c2ecf20Sopenharmony_ci	.idle_offset = 0x40,
9548c2ecf20Sopenharmony_ci	.ack_offset = 0x40,
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	.core_pwrcnt_offset = 0x48,
9578c2ecf20Sopenharmony_ci	.gpu_pwrcnt_offset = 0x50,
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	.core_power_transition_time = 24,
9608c2ecf20Sopenharmony_ci	.gpu_power_transition_time = 24,
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3368_pm_domains),
9638c2ecf20Sopenharmony_ci	.domain_info = rk3368_pm_domains,
9648c2ecf20Sopenharmony_ci};
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_cistatic const struct rockchip_pmu_info rk3399_pmu = {
9678c2ecf20Sopenharmony_ci	.pwr_offset = 0x14,
9688c2ecf20Sopenharmony_ci	.status_offset = 0x18,
9698c2ecf20Sopenharmony_ci	.req_offset = 0x60,
9708c2ecf20Sopenharmony_ci	.idle_offset = 0x64,
9718c2ecf20Sopenharmony_ci	.ack_offset = 0x68,
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	/* ARM Trusted Firmware manages power transition times */
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	.num_domains = ARRAY_SIZE(rk3399_pm_domains),
9768c2ecf20Sopenharmony_ci	.domain_info = rk3399_pm_domains,
9778c2ecf20Sopenharmony_ci};
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic const struct of_device_id rockchip_pm_domain_dt_match[] = {
9808c2ecf20Sopenharmony_ci	{
9818c2ecf20Sopenharmony_ci		.compatible = "rockchip,px30-power-controller",
9828c2ecf20Sopenharmony_ci		.data = (void *)&px30_pmu,
9838c2ecf20Sopenharmony_ci	},
9848c2ecf20Sopenharmony_ci	{
9858c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3036-power-controller",
9868c2ecf20Sopenharmony_ci		.data = (void *)&rk3036_pmu,
9878c2ecf20Sopenharmony_ci	},
9888c2ecf20Sopenharmony_ci	{
9898c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3066-power-controller",
9908c2ecf20Sopenharmony_ci		.data = (void *)&rk3066_pmu,
9918c2ecf20Sopenharmony_ci	},
9928c2ecf20Sopenharmony_ci	{
9938c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3128-power-controller",
9948c2ecf20Sopenharmony_ci		.data = (void *)&rk3128_pmu,
9958c2ecf20Sopenharmony_ci	},
9968c2ecf20Sopenharmony_ci	{
9978c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3188-power-controller",
9988c2ecf20Sopenharmony_ci		.data = (void *)&rk3188_pmu,
9998c2ecf20Sopenharmony_ci	},
10008c2ecf20Sopenharmony_ci	{
10018c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3228-power-controller",
10028c2ecf20Sopenharmony_ci		.data = (void *)&rk3228_pmu,
10038c2ecf20Sopenharmony_ci	},
10048c2ecf20Sopenharmony_ci	{
10058c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3288-power-controller",
10068c2ecf20Sopenharmony_ci		.data = (void *)&rk3288_pmu,
10078c2ecf20Sopenharmony_ci	},
10088c2ecf20Sopenharmony_ci	{
10098c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3328-power-controller",
10108c2ecf20Sopenharmony_ci		.data = (void *)&rk3328_pmu,
10118c2ecf20Sopenharmony_ci	},
10128c2ecf20Sopenharmony_ci	{
10138c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3366-power-controller",
10148c2ecf20Sopenharmony_ci		.data = (void *)&rk3366_pmu,
10158c2ecf20Sopenharmony_ci	},
10168c2ecf20Sopenharmony_ci	{
10178c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3368-power-controller",
10188c2ecf20Sopenharmony_ci		.data = (void *)&rk3368_pmu,
10198c2ecf20Sopenharmony_ci	},
10208c2ecf20Sopenharmony_ci	{
10218c2ecf20Sopenharmony_ci		.compatible = "rockchip,rk3399-power-controller",
10228c2ecf20Sopenharmony_ci		.data = (void *)&rk3399_pmu,
10238c2ecf20Sopenharmony_ci	},
10248c2ecf20Sopenharmony_ci	{ /* sentinel */ },
10258c2ecf20Sopenharmony_ci};
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_cistatic struct platform_driver rockchip_pm_domain_driver = {
10288c2ecf20Sopenharmony_ci	.probe = rockchip_pm_domain_probe,
10298c2ecf20Sopenharmony_ci	.driver = {
10308c2ecf20Sopenharmony_ci		.name   = "rockchip-pm-domain",
10318c2ecf20Sopenharmony_ci		.of_match_table = rockchip_pm_domain_dt_match,
10328c2ecf20Sopenharmony_ci		/*
10338c2ecf20Sopenharmony_ci		 * We can't forcibly eject devices form power domain,
10348c2ecf20Sopenharmony_ci		 * so we can't really remove power domains once they
10358c2ecf20Sopenharmony_ci		 * were added.
10368c2ecf20Sopenharmony_ci		 */
10378c2ecf20Sopenharmony_ci		.suppress_bind_attrs = true,
10388c2ecf20Sopenharmony_ci	},
10398c2ecf20Sopenharmony_ci};
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cistatic int __init rockchip_pm_domain_drv_register(void)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	return platform_driver_register(&rockchip_pm_domain_driver);
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_cipostcore_initcall(rockchip_pm_domain_drv_register);
1046