brintos

brintos / linux-shallow public Read only

0
0
Text · 46.0 KiB · cb0f938 Raw
1470 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Rockchip Generic power domain support.4 *5 * Copyright (c) 2015 ROCKCHIP, Co. Ltd.6 */7 8#include <linux/io.h>9#include <linux/iopoll.h>10#include <linux/err.h>11#include <linux/mutex.h>12#include <linux/platform_device.h>13#include <linux/pm_clock.h>14#include <linux/pm_domain.h>15#include <linux/property.h>16#include <linux/of.h>17#include <linux/of_address.h>18#include <linux/of_clk.h>19#include <linux/clk.h>20#include <linux/regmap.h>21#include <linux/mfd/syscon.h>22#include <soc/rockchip/pm_domains.h>23#include <dt-bindings/power/px30-power.h>24#include <dt-bindings/power/rockchip,rv1126-power.h>25#include <dt-bindings/power/rk3036-power.h>26#include <dt-bindings/power/rk3066-power.h>27#include <dt-bindings/power/rk3128-power.h>28#include <dt-bindings/power/rk3188-power.h>29#include <dt-bindings/power/rk3228-power.h>30#include <dt-bindings/power/rk3288-power.h>31#include <dt-bindings/power/rk3328-power.h>32#include <dt-bindings/power/rk3366-power.h>33#include <dt-bindings/power/rk3368-power.h>34#include <dt-bindings/power/rk3399-power.h>35#include <dt-bindings/power/rk3568-power.h>36#include <dt-bindings/power/rockchip,rk3576-power.h>37#include <dt-bindings/power/rk3588-power.h>38 39struct rockchip_domain_info {40	const char *name;41	int pwr_mask;42	int status_mask;43	int req_mask;44	int idle_mask;45	int ack_mask;46	bool active_wakeup;47	int pwr_w_mask;48	int req_w_mask;49	int clk_ungate_mask;50	int mem_status_mask;51	int repair_status_mask;52	u32 pwr_offset;53	u32 mem_offset;54	u32 req_offset;55};56 57struct rockchip_pmu_info {58	u32 pwr_offset;59	u32 status_offset;60	u32 req_offset;61	u32 idle_offset;62	u32 ack_offset;63	u32 mem_pwr_offset;64	u32 chain_status_offset;65	u32 mem_status_offset;66	u32 repair_status_offset;67	u32 clk_ungate_offset;68 69	u32 core_pwrcnt_offset;70	u32 gpu_pwrcnt_offset;71 72	unsigned int core_power_transition_time;73	unsigned int gpu_power_transition_time;74 75	int num_domains;76	const struct rockchip_domain_info *domain_info;77};78 79#define MAX_QOS_REGS_NUM	580#define QOS_PRIORITY		0x0881#define QOS_MODE		0x0c82#define QOS_BANDWIDTH		0x1083#define QOS_SATURATION		0x1484#define QOS_EXTCONTROL		0x1885 86struct rockchip_pm_domain {87	struct generic_pm_domain genpd;88	const struct rockchip_domain_info *info;89	struct rockchip_pmu *pmu;90	int num_qos;91	struct regmap **qos_regmap;92	u32 *qos_save_regs[MAX_QOS_REGS_NUM];93	int num_clks;94	struct clk_bulk_data *clks;95};96 97struct rockchip_pmu {98	struct device *dev;99	struct regmap *regmap;100	const struct rockchip_pmu_info *info;101	struct mutex mutex; /* mutex lock for pmu */102	struct genpd_onecell_data genpd_data;103	struct generic_pm_domain *domains[];104};105 106#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)107 108#define DOMAIN(_name, pwr, status, req, idle, ack, wakeup)	\109{							\110	.name = _name,				\111	.pwr_mask = (pwr),				\112	.status_mask = (status),			\113	.req_mask = (req),				\114	.idle_mask = (idle),				\115	.ack_mask = (ack),				\116	.active_wakeup = (wakeup),			\117}118 119#define DOMAIN_M(_name, pwr, status, req, idle, ack, wakeup)	\120{							\121	.name = _name,				\122	.pwr_w_mask = (pwr) << 16,			\123	.pwr_mask = (pwr),				\124	.status_mask = (status),			\125	.req_w_mask = (req) << 16,			\126	.req_mask = (req),				\127	.idle_mask = (idle),				\128	.ack_mask = (ack),				\129	.active_wakeup = wakeup,			\130}131 132#define DOMAIN_M_O_R(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, wakeup)	\133{							\134	.name = _name,					\135	.pwr_offset = p_offset,				\136	.pwr_w_mask = (pwr) << 16,			\137	.pwr_mask = (pwr),				\138	.status_mask = (status),			\139	.mem_offset = m_offset,				\140	.mem_status_mask = (m_status),			\141	.repair_status_mask = (r_status),		\142	.req_offset = r_offset,				\143	.req_w_mask = (req) << 16,			\144	.req_mask = (req),				\145	.idle_mask = (idle),				\146	.ack_mask = (ack),				\147	.active_wakeup = wakeup,			\148}149 150#define DOMAIN_M_O_R_G(_name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, ack, g_mask, wakeup)	\151{							\152	.name = _name,					\153	.pwr_offset = p_offset,				\154	.pwr_w_mask = (pwr) << 16,			\155	.pwr_mask = (pwr),				\156	.status_mask = (status),			\157	.mem_offset = m_offset,				\158	.mem_status_mask = (m_status),			\159	.repair_status_mask = (r_status),		\160	.req_offset = r_offset,				\161	.req_w_mask = (req) << 16,			\162	.req_mask = (req),				\163	.idle_mask = (idle),				\164	.clk_ungate_mask = (g_mask),			\165	.ack_mask = (ack),				\166	.active_wakeup = wakeup,			\167}168 169#define DOMAIN_RK3036(_name, req, ack, idle, wakeup)		\170{							\171	.name = _name,				\172	.req_mask = (req),				\173	.req_w_mask = (req) << 16,			\174	.ack_mask = (ack),				\175	.idle_mask = (idle),				\176	.active_wakeup = wakeup,			\177}178 179#define DOMAIN_PX30(name, pwr, status, req, wakeup)		\180	DOMAIN_M(name, pwr, status, req, (req) << 16, req, wakeup)181 182#define DOMAIN_RV1126(name, pwr, req, idle, wakeup)		\183	DOMAIN_M(name, pwr, pwr, req, idle, idle, wakeup)184 185#define DOMAIN_RK3288(name, pwr, status, req, wakeup)		\186	DOMAIN(name, pwr, status, req, req, (req) << 16, wakeup)187 188#define DOMAIN_RK3328(name, pwr, status, req, wakeup)		\189	DOMAIN_M(name, pwr, pwr, req, (req) << 10, req, wakeup)190 191#define DOMAIN_RK3368(name, pwr, status, req, wakeup)		\192	DOMAIN(name, pwr, status, req, (req) << 16, req, wakeup)193 194#define DOMAIN_RK3399(name, pwr, status, req, wakeup)		\195	DOMAIN(name, pwr, status, req, req, req, wakeup)196 197#define DOMAIN_RK3568(name, pwr, req, wakeup)		\198	DOMAIN_M(name, pwr, pwr, req, req, req, wakeup)199 200#define DOMAIN_RK3576(name, p_offset, pwr, status, r_status, r_offset, req, idle, g_mask, wakeup)	\201	DOMAIN_M_O_R_G(name, p_offset, pwr, status, 0, r_status, r_status, r_offset, req, idle, idle, g_mask, wakeup)202 203/*204 * Dynamic Memory Controller may need to coordinate with us -- see205 * rockchip_pmu_block().206 *207 * dmc_pmu_mutex protects registration-time races, so DMC driver doesn't try to208 * block() while we're initializing the PMU.209 */210static DEFINE_MUTEX(dmc_pmu_mutex);211static struct rockchip_pmu *dmc_pmu;212 213/*214 * Block PMU transitions and make sure they don't interfere with ARM Trusted215 * Firmware operations. There are two conflicts, noted in the comments below.216 *217 * Caller must unblock PMU transitions via rockchip_pmu_unblock().218 */219int rockchip_pmu_block(void)220{221	struct rockchip_pmu *pmu;222	struct generic_pm_domain *genpd;223	struct rockchip_pm_domain *pd;224	int i, ret;225 226	mutex_lock(&dmc_pmu_mutex);227 228	/* No PMU (yet)? Then we just block rockchip_pmu_probe(). */229	if (!dmc_pmu)230		return 0;231	pmu = dmc_pmu;232 233	/*234	 * mutex blocks all idle transitions: we can't touch the235	 * PMU_BUS_IDLE_REQ (our ".idle_offset") register while ARM Trusted236	 * Firmware might be using it.237	 */238	mutex_lock(&pmu->mutex);239 240	/*241	 * Power domain clocks: Per Rockchip, we *must* keep certain clocks242	 * enabled for the duration of power-domain transitions. Most243	 * transitions are handled by this driver, but some cases (in244	 * particular, DRAM DVFS / memory-controller idle) must be handled by245	 * firmware. Firmware can handle most clock management via a special246	 * "ungate" register (PMU_CRU_GATEDIS_CON0), but unfortunately, this247	 * doesn't handle PLLs. We can assist this transition by doing the248	 * clock management on behalf of firmware.249	 */250	for (i = 0; i < pmu->genpd_data.num_domains; i++) {251		genpd = pmu->genpd_data.domains[i];252		if (genpd) {253			pd = to_rockchip_pd(genpd);254			ret = clk_bulk_enable(pd->num_clks, pd->clks);255			if (ret < 0) {256				dev_err(pmu->dev,257					"failed to enable clks for domain '%s': %d\n",258					genpd->name, ret);259				goto err;260			}261		}262	}263 264	return 0;265 266err:267	for (i = i - 1; i >= 0; i--) {268		genpd = pmu->genpd_data.domains[i];269		if (genpd) {270			pd = to_rockchip_pd(genpd);271			clk_bulk_disable(pd->num_clks, pd->clks);272		}273	}274	mutex_unlock(&pmu->mutex);275	mutex_unlock(&dmc_pmu_mutex);276 277	return ret;278}279EXPORT_SYMBOL_GPL(rockchip_pmu_block);280 281/* Unblock PMU transitions. */282void rockchip_pmu_unblock(void)283{284	struct rockchip_pmu *pmu;285	struct generic_pm_domain *genpd;286	struct rockchip_pm_domain *pd;287	int i;288 289	if (dmc_pmu) {290		pmu = dmc_pmu;291		for (i = 0; i < pmu->genpd_data.num_domains; i++) {292			genpd = pmu->genpd_data.domains[i];293			if (genpd) {294				pd = to_rockchip_pd(genpd);295				clk_bulk_disable(pd->num_clks, pd->clks);296			}297		}298 299		mutex_unlock(&pmu->mutex);300	}301 302	mutex_unlock(&dmc_pmu_mutex);303}304EXPORT_SYMBOL_GPL(rockchip_pmu_unblock);305 306#define DOMAIN_RK3588(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, wakeup)	\307	DOMAIN_M_O_R(name, p_offset, pwr, status, m_offset, m_status, r_status, r_offset, req, idle, idle, wakeup)308 309static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)310{311	struct rockchip_pmu *pmu = pd->pmu;312	const struct rockchip_domain_info *pd_info = pd->info;313	unsigned int val;314 315	regmap_read(pmu->regmap, pmu->info->idle_offset, &val);316	return (val & pd_info->idle_mask) == pd_info->idle_mask;317}318 319static unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu)320{321	unsigned int val;322 323	regmap_read(pmu->regmap, pmu->info->ack_offset, &val);324	return val;325}326 327static int rockchip_pmu_ungate_clk(struct rockchip_pm_domain *pd, bool ungate)328{329	const struct rockchip_domain_info *pd_info = pd->info;330	struct rockchip_pmu *pmu = pd->pmu;331	unsigned int val;332	int clk_ungate_w_mask = pd_info->clk_ungate_mask << 16;333 334	if (!pd_info->clk_ungate_mask)335		return 0;336 337	if (!pmu->info->clk_ungate_offset)338		return 0;339 340	val = ungate ? (pd_info->clk_ungate_mask | clk_ungate_w_mask) :341			clk_ungate_w_mask;342	regmap_write(pmu->regmap, pmu->info->clk_ungate_offset, val);343 344	return 0;345}346 347static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,348					 bool idle)349{350	const struct rockchip_domain_info *pd_info = pd->info;351	struct generic_pm_domain *genpd = &pd->genpd;352	struct rockchip_pmu *pmu = pd->pmu;353	u32 pd_req_offset = pd_info->req_offset;354	unsigned int target_ack;355	unsigned int val;356	bool is_idle;357	int ret;358 359	if (pd_info->req_mask == 0)360		return 0;361	else if (pd_info->req_w_mask)362		regmap_write(pmu->regmap, pmu->info->req_offset + pd_req_offset,363			     idle ? (pd_info->req_mask | pd_info->req_w_mask) :364			     pd_info->req_w_mask);365	else366		regmap_update_bits(pmu->regmap, pmu->info->req_offset + pd_req_offset,367				   pd_info->req_mask, idle ? -1U : 0);368 369	wmb();370 371	/* Wait util idle_ack = 1 */372	target_ack = idle ? pd_info->ack_mask : 0;373	ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val,374					(val & pd_info->ack_mask) == target_ack,375					0, 10000);376	if (ret) {377		dev_err(pmu->dev,378			"failed to get ack on domain '%s', val=0x%x\n",379			genpd->name, val);380		return ret;381	}382 383	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd,384					is_idle, is_idle == idle, 0, 10000);385	if (ret) {386		dev_err(pmu->dev,387			"failed to set idle on domain '%s', val=%d\n",388			genpd->name, is_idle);389		return ret;390	}391 392	return 0;393}394 395static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)396{397	int i;398 399	for (i = 0; i < pd->num_qos; i++) {400		regmap_read(pd->qos_regmap[i],401			    QOS_PRIORITY,402			    &pd->qos_save_regs[0][i]);403		regmap_read(pd->qos_regmap[i],404			    QOS_MODE,405			    &pd->qos_save_regs[1][i]);406		regmap_read(pd->qos_regmap[i],407			    QOS_BANDWIDTH,408			    &pd->qos_save_regs[2][i]);409		regmap_read(pd->qos_regmap[i],410			    QOS_SATURATION,411			    &pd->qos_save_regs[3][i]);412		regmap_read(pd->qos_regmap[i],413			    QOS_EXTCONTROL,414			    &pd->qos_save_regs[4][i]);415	}416	return 0;417}418 419static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd)420{421	int i;422 423	for (i = 0; i < pd->num_qos; i++) {424		regmap_write(pd->qos_regmap[i],425			     QOS_PRIORITY,426			     pd->qos_save_regs[0][i]);427		regmap_write(pd->qos_regmap[i],428			     QOS_MODE,429			     pd->qos_save_regs[1][i]);430		regmap_write(pd->qos_regmap[i],431			     QOS_BANDWIDTH,432			     pd->qos_save_regs[2][i]);433		regmap_write(pd->qos_regmap[i],434			     QOS_SATURATION,435			     pd->qos_save_regs[3][i]);436		regmap_write(pd->qos_regmap[i],437			     QOS_EXTCONTROL,438			     pd->qos_save_regs[4][i]);439	}440 441	return 0;442}443 444static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)445{446	struct rockchip_pmu *pmu = pd->pmu;447	unsigned int val;448 449	if (pd->info->repair_status_mask) {450		regmap_read(pmu->regmap, pmu->info->repair_status_offset, &val);451		/* 1'b1: power on, 1'b0: power off */452		return val & pd->info->repair_status_mask;453	}454 455	/* check idle status for idle-only domains */456	if (pd->info->status_mask == 0)457		return !rockchip_pmu_domain_is_idle(pd);458 459	regmap_read(pmu->regmap, pmu->info->status_offset, &val);460 461	/* 1'b0: power on, 1'b1: power off */462	return !(val & pd->info->status_mask);463}464 465static bool rockchip_pmu_domain_is_mem_on(struct rockchip_pm_domain *pd)466{467	struct rockchip_pmu *pmu = pd->pmu;468	unsigned int val;469 470	regmap_read(pmu->regmap,471		    pmu->info->mem_status_offset + pd->info->mem_offset, &val);472 473	/* 1'b0: power on, 1'b1: power off */474	return !(val & pd->info->mem_status_mask);475}476 477static bool rockchip_pmu_domain_is_chain_on(struct rockchip_pm_domain *pd)478{479	struct rockchip_pmu *pmu = pd->pmu;480	unsigned int val;481 482	regmap_read(pmu->regmap,483		    pmu->info->chain_status_offset + pd->info->mem_offset, &val);484 485	/* 1'b1: power on, 1'b0: power off */486	return val & pd->info->mem_status_mask;487}488 489static int rockchip_pmu_domain_mem_reset(struct rockchip_pm_domain *pd)490{491	struct rockchip_pmu *pmu = pd->pmu;492	struct generic_pm_domain *genpd = &pd->genpd;493	bool is_on;494	int ret = 0;495 496	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_chain_on, pd, is_on,497					is_on == true, 0, 10000);498	if (ret) {499		dev_err(pmu->dev,500			"failed to get chain status '%s', target_on=1, val=%d\n",501			genpd->name, is_on);502		goto error;503	}504 505	udelay(20);506 507	regmap_write(pmu->regmap, pmu->info->mem_pwr_offset + pd->info->pwr_offset,508		     (pd->info->pwr_mask | pd->info->pwr_w_mask));509	wmb();510 511	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_mem_on, pd, is_on,512					is_on == false, 0, 10000);513	if (ret) {514		dev_err(pmu->dev,515			"failed to get mem status '%s', target_on=0, val=%d\n",516			genpd->name, is_on);517		goto error;518	}519 520	regmap_write(pmu->regmap, pmu->info->mem_pwr_offset + pd->info->pwr_offset,521		     pd->info->pwr_w_mask);522	wmb();523 524	ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_mem_on, pd, is_on,525					is_on == true, 0, 10000);526	if (ret) {527		dev_err(pmu->dev,528			"failed to get mem status '%s', target_on=1, val=%d\n",529			genpd->name, is_on);530	}531 532error:533	return ret;534}535 536static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,537					     bool on)538{539	struct rockchip_pmu *pmu = pd->pmu;540	struct generic_pm_domain *genpd = &pd->genpd;541	u32 pd_pwr_offset = pd->info->pwr_offset;542	bool is_on, is_mem_on = false;543 544	if (pd->info->pwr_mask == 0)545		return;546 547	if (on && pd->info->mem_status_mask)548		is_mem_on = rockchip_pmu_domain_is_mem_on(pd);549 550	if (pd->info->pwr_w_mask)551		regmap_write(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset,552			     on ? pd->info->pwr_w_mask :553			     (pd->info->pwr_mask | pd->info->pwr_w_mask));554	else555		regmap_update_bits(pmu->regmap, pmu->info->pwr_offset + pd_pwr_offset,556				   pd->info->pwr_mask, on ? 0 : -1U);557 558	wmb();559 560	if (is_mem_on && rockchip_pmu_domain_mem_reset(pd))561		return;562 563	if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,564				      is_on == on, 0, 10000)) {565		dev_err(pmu->dev,566			"failed to set domain '%s', val=%d\n",567			genpd->name, is_on);568		return;569	}570}571 572static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)573{574	struct rockchip_pmu *pmu = pd->pmu;575	int ret;576 577	mutex_lock(&pmu->mutex);578 579	if (rockchip_pmu_domain_is_on(pd) != power_on) {580		ret = clk_bulk_enable(pd->num_clks, pd->clks);581		if (ret < 0) {582			dev_err(pmu->dev, "failed to enable clocks\n");583			mutex_unlock(&pmu->mutex);584			return ret;585		}586 587		rockchip_pmu_ungate_clk(pd, true);588 589		if (!power_on) {590			rockchip_pmu_save_qos(pd);591 592			/* if powering down, idle request to NIU first */593			rockchip_pmu_set_idle_request(pd, true);594		}595 596		rockchip_do_pmu_set_power_domain(pd, power_on);597 598		if (power_on) {599			/* if powering up, leave idle mode */600			rockchip_pmu_set_idle_request(pd, false);601 602			rockchip_pmu_restore_qos(pd);603		}604 605		rockchip_pmu_ungate_clk(pd, false);606		clk_bulk_disable(pd->num_clks, pd->clks);607	}608 609	mutex_unlock(&pmu->mutex);610	return 0;611}612 613static int rockchip_pd_power_on(struct generic_pm_domain *domain)614{615	struct rockchip_pm_domain *pd = to_rockchip_pd(domain);616 617	return rockchip_pd_power(pd, true);618}619 620static int rockchip_pd_power_off(struct generic_pm_domain *domain)621{622	struct rockchip_pm_domain *pd = to_rockchip_pd(domain);623 624	return rockchip_pd_power(pd, false);625}626 627static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,628				  struct device *dev)629{630	struct clk *clk;631	int i;632	int error;633 634	dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);635 636	error = pm_clk_create(dev);637	if (error) {638		dev_err(dev, "pm_clk_create failed %d\n", error);639		return error;640	}641 642	i = 0;643	while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {644		dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);645		error = pm_clk_add_clk(dev, clk);646		if (error) {647			dev_err(dev, "pm_clk_add_clk failed %d\n", error);648			clk_put(clk);649			pm_clk_destroy(dev);650			return error;651		}652	}653 654	return 0;655}656 657static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,658				   struct device *dev)659{660	dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);661 662	pm_clk_destroy(dev);663}664 665static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,666				      struct device_node *node)667{668	const struct rockchip_domain_info *pd_info;669	struct rockchip_pm_domain *pd;670	struct device_node *qos_node;671	int i, j;672	u32 id;673	int error;674 675	error = of_property_read_u32(node, "reg", &id);676	if (error) {677		dev_err(pmu->dev,678			"%pOFn: failed to retrieve domain id (reg): %d\n",679			node, error);680		return -EINVAL;681	}682 683	if (id >= pmu->info->num_domains) {684		dev_err(pmu->dev, "%pOFn: invalid domain id %d\n",685			node, id);686		return -EINVAL;687	}688	/* RK3588 has domains with two parents (RKVDEC0/RKVDEC1) */689	if (pmu->genpd_data.domains[id])690		return 0;691 692	pd_info = &pmu->info->domain_info[id];693	if (!pd_info) {694		dev_err(pmu->dev, "%pOFn: undefined domain id %d\n",695			node, id);696		return -EINVAL;697	}698 699	pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);700	if (!pd)701		return -ENOMEM;702 703	pd->info = pd_info;704	pd->pmu = pmu;705 706	pd->num_clks = of_clk_get_parent_count(node);707	if (pd->num_clks > 0) {708		pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,709					sizeof(*pd->clks), GFP_KERNEL);710		if (!pd->clks)711			return -ENOMEM;712	} else {713		dev_dbg(pmu->dev, "%pOFn: doesn't have clocks: %d\n",714			node, pd->num_clks);715		pd->num_clks = 0;716	}717 718	for (i = 0; i < pd->num_clks; i++) {719		pd->clks[i].clk = of_clk_get(node, i);720		if (IS_ERR(pd->clks[i].clk)) {721			error = PTR_ERR(pd->clks[i].clk);722			dev_err(pmu->dev,723				"%pOFn: failed to get clk at index %d: %d\n",724				node, i, error);725			return error;726		}727	}728 729	error = clk_bulk_prepare(pd->num_clks, pd->clks);730	if (error)731		goto err_put_clocks;732 733	pd->num_qos = of_count_phandle_with_args(node, "pm_qos",734						 NULL);735 736	if (pd->num_qos > 0) {737		pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,738					      sizeof(*pd->qos_regmap),739					      GFP_KERNEL);740		if (!pd->qos_regmap) {741			error = -ENOMEM;742			goto err_unprepare_clocks;743		}744 745		for (j = 0; j < MAX_QOS_REGS_NUM; j++) {746			pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,747							    pd->num_qos,748							    sizeof(u32),749							    GFP_KERNEL);750			if (!pd->qos_save_regs[j]) {751				error = -ENOMEM;752				goto err_unprepare_clocks;753			}754		}755 756		for (j = 0; j < pd->num_qos; j++) {757			qos_node = of_parse_phandle(node, "pm_qos", j);758			if (!qos_node) {759				error = -ENODEV;760				goto err_unprepare_clocks;761			}762			pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);763			of_node_put(qos_node);764			if (IS_ERR(pd->qos_regmap[j])) {765				error = -ENODEV;766				goto err_unprepare_clocks;767			}768		}769	}770 771	if (pd->info->name)772		pd->genpd.name = pd->info->name;773	else774		pd->genpd.name = kbasename(node->full_name);775	pd->genpd.power_off = rockchip_pd_power_off;776	pd->genpd.power_on = rockchip_pd_power_on;777	pd->genpd.attach_dev = rockchip_pd_attach_dev;778	pd->genpd.detach_dev = rockchip_pd_detach_dev;779	pd->genpd.flags = GENPD_FLAG_PM_CLK;780	if (pd_info->active_wakeup)781		pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;782	pm_genpd_init(&pd->genpd, NULL,783		      !rockchip_pmu_domain_is_on(pd) ||784		      (pd->info->mem_status_mask && !rockchip_pmu_domain_is_mem_on(pd)));785 786	pmu->genpd_data.domains[id] = &pd->genpd;787	return 0;788 789err_unprepare_clocks:790	clk_bulk_unprepare(pd->num_clks, pd->clks);791err_put_clocks:792	clk_bulk_put(pd->num_clks, pd->clks);793	return error;794}795 796static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)797{798	int ret;799 800	/*801	 * We're in the error cleanup already, so we only complain,802	 * but won't emit another error on top of the original one.803	 */804	ret = pm_genpd_remove(&pd->genpd);805	if (ret < 0)806		dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",807			pd->genpd.name, ret);808 809	clk_bulk_unprepare(pd->num_clks, pd->clks);810	clk_bulk_put(pd->num_clks, pd->clks);811 812	/* protect the zeroing of pm->num_clks */813	mutex_lock(&pd->pmu->mutex);814	pd->num_clks = 0;815	mutex_unlock(&pd->pmu->mutex);816 817	/* devm will free our memory */818}819 820static void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)821{822	struct generic_pm_domain *genpd;823	struct rockchip_pm_domain *pd;824	int i;825 826	for (i = 0; i < pmu->genpd_data.num_domains; i++) {827		genpd = pmu->genpd_data.domains[i];828		if (genpd) {829			pd = to_rockchip_pd(genpd);830			rockchip_pm_remove_one_domain(pd);831		}832	}833 834	/* devm will free our memory */835}836 837static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,838				      u32 domain_reg_offset,839				      unsigned int count)840{841	/* First configure domain power down transition count ... */842	regmap_write(pmu->regmap, domain_reg_offset, count);843	/* ... and then power up count. */844	regmap_write(pmu->regmap, domain_reg_offset + 4, count);845}846 847static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,848				     struct device_node *parent)849{850	struct generic_pm_domain *child_domain, *parent_domain;851	int error;852 853	for_each_child_of_node_scoped(parent, np) {854		u32 idx;855 856		error = of_property_read_u32(parent, "reg", &idx);857		if (error) {858			dev_err(pmu->dev,859				"%pOFn: failed to retrieve domain id (reg): %d\n",860				parent, error);861			return error;862		}863		parent_domain = pmu->genpd_data.domains[idx];864 865		error = rockchip_pm_add_one_domain(pmu, np);866		if (error) {867			dev_err(pmu->dev, "failed to handle node %pOFn: %d\n",868				np, error);869			return error;870		}871 872		error = of_property_read_u32(np, "reg", &idx);873		if (error) {874			dev_err(pmu->dev,875				"%pOFn: failed to retrieve domain id (reg): %d\n",876				np, error);877			return error;878		}879		child_domain = pmu->genpd_data.domains[idx];880 881		error = pm_genpd_add_subdomain(parent_domain, child_domain);882		if (error) {883			dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n",884				parent_domain->name, child_domain->name, error);885			return error;886		} else {887			dev_dbg(pmu->dev, "%s add subdomain: %s\n",888				parent_domain->name, child_domain->name);889		}890 891		rockchip_pm_add_subdomain(pmu, np);892	}893 894	return 0;895}896 897static int rockchip_pm_domain_probe(struct platform_device *pdev)898{899	struct device *dev = &pdev->dev;900	struct device_node *np = dev->of_node;901	struct device *parent;902	struct rockchip_pmu *pmu;903	const struct rockchip_pmu_info *pmu_info;904	int error;905 906	if (!np) {907		dev_err(dev, "device tree node not found\n");908		return -ENODEV;909	}910 911	pmu_info = device_get_match_data(dev);912 913	pmu = devm_kzalloc(dev,914			   struct_size(pmu, domains, pmu_info->num_domains),915			   GFP_KERNEL);916	if (!pmu)917		return -ENOMEM;918 919	pmu->dev = &pdev->dev;920	mutex_init(&pmu->mutex);921 922	pmu->info = pmu_info;923 924	pmu->genpd_data.domains = pmu->domains;925	pmu->genpd_data.num_domains = pmu_info->num_domains;926 927	parent = dev->parent;928	if (!parent) {929		dev_err(dev, "no parent for syscon devices\n");930		return -ENODEV;931	}932 933	pmu->regmap = syscon_node_to_regmap(parent->of_node);934	if (IS_ERR(pmu->regmap)) {935		dev_err(dev, "no regmap available\n");936		return PTR_ERR(pmu->regmap);937	}938 939	/*940	 * Configure power up and down transition delays for CORE941	 * and GPU domains.942	 */943	if (pmu_info->core_power_transition_time)944		rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,945					pmu_info->core_power_transition_time);946	if (pmu_info->gpu_pwrcnt_offset)947		rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,948					pmu_info->gpu_power_transition_time);949 950	error = -ENODEV;951 952	/*953	 * Prevent any rockchip_pmu_block() from racing with the remainder of954	 * setup (clocks, register initialization).955	 */956	guard(mutex)(&dmc_pmu_mutex);957 958	for_each_available_child_of_node_scoped(np, node) {959		error = rockchip_pm_add_one_domain(pmu, node);960		if (error) {961			dev_err(dev, "failed to handle node %pOFn: %d\n",962				node, error);963			goto err_out;964		}965 966		error = rockchip_pm_add_subdomain(pmu, node);967		if (error < 0) {968			dev_err(dev, "failed to handle subdomain node %pOFn: %d\n",969				node, error);970			goto err_out;971		}972	}973 974	if (error) {975		dev_dbg(dev, "no power domains defined\n");976		goto err_out;977	}978 979	error = of_genpd_add_provider_onecell(np, &pmu->genpd_data);980	if (error) {981		dev_err(dev, "failed to add provider: %d\n", error);982		goto err_out;983	}984 985	/* We only expect one PMU. */986	if (!WARN_ON_ONCE(dmc_pmu))987		dmc_pmu = pmu;988 989	return 0;990 991err_out:992	rockchip_pm_domain_cleanup(pmu);993	return error;994}995 996static const struct rockchip_domain_info px30_pm_domains[] = {997	[PX30_PD_USB]		= DOMAIN_PX30("usb",      BIT(5),  BIT(5),  BIT(10), false),998	[PX30_PD_SDCARD]	= DOMAIN_PX30("sdcard",   BIT(8),  BIT(8),  BIT(9),  false),999	[PX30_PD_GMAC]		= DOMAIN_PX30("gmac",     BIT(10), BIT(10), BIT(6),  false),1000	[PX30_PD_MMC_NAND]	= DOMAIN_PX30("mmc_nand", BIT(11), BIT(11), BIT(5),  false),1001	[PX30_PD_VPU]		= DOMAIN_PX30("vpu",      BIT(12), BIT(12), BIT(14), false),1002	[PX30_PD_VO]		= DOMAIN_PX30("vo",       BIT(13), BIT(13), BIT(7),  false),1003	[PX30_PD_VI]		= DOMAIN_PX30("vi",       BIT(14), BIT(14), BIT(8),  false),1004	[PX30_PD_GPU]		= DOMAIN_PX30("gpu",      BIT(15), BIT(15), BIT(2),  false),1005};1006 1007static const struct rockchip_domain_info rv1126_pm_domains[] = {1008	[RV1126_PD_VEPU]	= DOMAIN_RV1126("vepu", BIT(2),  BIT(9),  BIT(9), false),1009	[RV1126_PD_VI]		= DOMAIN_RV1126("vi", BIT(4),  BIT(6),  BIT(6),  false),1010	[RV1126_PD_VO]		= DOMAIN_RV1126("vo", BIT(5),  BIT(7),  BIT(7),  false),1011	[RV1126_PD_ISPP]	= DOMAIN_RV1126("ispp", BIT(1), BIT(8), BIT(8),  false),1012	[RV1126_PD_VDPU]	= DOMAIN_RV1126("vdpu", BIT(3), BIT(10), BIT(10), false),1013	[RV1126_PD_NVM]		= DOMAIN_RV1126("nvm", BIT(7), BIT(11), BIT(11),  false),1014	[RV1126_PD_SDIO]	= DOMAIN_RV1126("sdio", BIT(8), BIT(13), BIT(13),  false),1015	[RV1126_PD_USB]		= DOMAIN_RV1126("usb", BIT(9), BIT(15), BIT(15),  false),1016};1017 1018static const struct rockchip_domain_info rk3036_pm_domains[] = {1019	[RK3036_PD_MSCH]	= DOMAIN_RK3036("msch", BIT(14), BIT(23), BIT(30), true),1020	[RK3036_PD_CORE]	= DOMAIN_RK3036("core", BIT(13), BIT(17), BIT(24), false),1021	[RK3036_PD_PERI]	= DOMAIN_RK3036("peri", BIT(12), BIT(18), BIT(25), false),1022	[RK3036_PD_VIO]		= DOMAIN_RK3036("vio",  BIT(11), BIT(19), BIT(26), false),1023	[RK3036_PD_VPU]		= DOMAIN_RK3036("vpu",  BIT(10), BIT(20), BIT(27), false),1024	[RK3036_PD_GPU]		= DOMAIN_RK3036("gpu",  BIT(9),  BIT(21), BIT(28), false),1025	[RK3036_PD_SYS]		= DOMAIN_RK3036("sys",  BIT(8),  BIT(22), BIT(29), false),1026};1027 1028static const struct rockchip_domain_info rk3066_pm_domains[] = {1029	[RK3066_PD_GPU]		= DOMAIN("gpu",   BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),1030	[RK3066_PD_VIDEO]	= DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),1031	[RK3066_PD_VIO]		= DOMAIN("vio",   BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),1032	[RK3066_PD_PERI]	= DOMAIN("peri",  BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),1033	[RK3066_PD_CPU]		= DOMAIN("cpu",   0,      BIT(5), BIT(1), BIT(26), BIT(31), false),1034};1035 1036static const struct rockchip_domain_info rk3128_pm_domains[] = {1037	[RK3128_PD_CORE]	= DOMAIN_RK3288("core",  BIT(0), BIT(0), BIT(4), false),1038	[RK3128_PD_MSCH]	= DOMAIN_RK3288("msch",  0,      0,      BIT(6), true),1039	[RK3128_PD_VIO]		= DOMAIN_RK3288("vio",   BIT(3), BIT(3), BIT(2), false),1040	[RK3128_PD_VIDEO]	= DOMAIN_RK3288("video", BIT(2), BIT(2), BIT(1), false),1041	[RK3128_PD_GPU]		= DOMAIN_RK3288("gpu",   BIT(1), BIT(1), BIT(3), false),1042};1043 1044static const struct rockchip_domain_info rk3188_pm_domains[] = {1045	[RK3188_PD_GPU]		= DOMAIN("gpu",   BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),1046	[RK3188_PD_VIDEO]	= DOMAIN("video", BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),1047	[RK3188_PD_VIO]		= DOMAIN("vio",   BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),1048	[RK3188_PD_PERI]	= DOMAIN("peri",  BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),1049	[RK3188_PD_CPU]		= DOMAIN("cpu",   BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false),1050};1051 1052static const struct rockchip_domain_info rk3228_pm_domains[] = {1053	[RK3228_PD_CORE]	= DOMAIN_RK3036("core", BIT(0),  BIT(0),  BIT(16), true),1054	[RK3228_PD_MSCH]	= DOMAIN_RK3036("msch", BIT(1),  BIT(1),  BIT(17), true),1055	[RK3228_PD_BUS]		= DOMAIN_RK3036("bus",  BIT(2),  BIT(2),  BIT(18), true),1056	[RK3228_PD_SYS]		= DOMAIN_RK3036("sys",  BIT(3),  BIT(3),  BIT(19), true),1057	[RK3228_PD_VIO]		= DOMAIN_RK3036("vio",  BIT(4),  BIT(4),  BIT(20), false),1058	[RK3228_PD_VOP]		= DOMAIN_RK3036("vop",  BIT(5),  BIT(5),  BIT(21), false),1059	[RK3228_PD_VPU]		= DOMAIN_RK3036("vpu",  BIT(6),  BIT(6),  BIT(22), false),1060	[RK3228_PD_RKVDEC]	= DOMAIN_RK3036("vdec", BIT(7),  BIT(7),  BIT(23), false),1061	[RK3228_PD_GPU]		= DOMAIN_RK3036("gpu",  BIT(8),  BIT(8),  BIT(24), false),1062	[RK3228_PD_PERI]	= DOMAIN_RK3036("peri", BIT(9),  BIT(9),  BIT(25), true),1063	[RK3228_PD_GMAC]	= DOMAIN_RK3036("gmac", BIT(10), BIT(10), BIT(26), false),1064};1065 1066static const struct rockchip_domain_info rk3288_pm_domains[] = {1067	[RK3288_PD_VIO]		= DOMAIN_RK3288("vio",   BIT(7),  BIT(7),  BIT(4), false),1068	[RK3288_PD_HEVC]	= DOMAIN_RK3288("hevc",  BIT(14), BIT(10), BIT(9), false),1069	[RK3288_PD_VIDEO]	= DOMAIN_RK3288("video", BIT(8),  BIT(8),  BIT(3), false),1070	[RK3288_PD_GPU]		= DOMAIN_RK3288("gpu",   BIT(9),  BIT(9),  BIT(2), false),1071};1072 1073static const struct rockchip_domain_info rk3328_pm_domains[] = {1074	[RK3328_PD_CORE]	= DOMAIN_RK3328("core",  0, BIT(0), BIT(0), false),1075	[RK3328_PD_GPU]		= DOMAIN_RK3328("gpu",   0, BIT(1), BIT(1), false),1076	[RK3328_PD_BUS]		= DOMAIN_RK3328("bus",   0, BIT(2), BIT(2), true),1077	[RK3328_PD_MSCH]	= DOMAIN_RK3328("msch",  0, BIT(3), BIT(3), true),1078	[RK3328_PD_PERI]	= DOMAIN_RK3328("peri",  0, BIT(4), BIT(4), true),1079	[RK3328_PD_VIDEO]	= DOMAIN_RK3328("video", 0, BIT(5), BIT(5), false),1080	[RK3328_PD_HEVC]	= DOMAIN_RK3328("hevc",  0, BIT(6), BIT(6), false),1081	[RK3328_PD_VIO]		= DOMAIN_RK3328("vio",   0, BIT(8), BIT(8), false),1082	[RK3328_PD_VPU]		= DOMAIN_RK3328("vpu",   0, BIT(9), BIT(9), false),1083};1084 1085static const struct rockchip_domain_info rk3366_pm_domains[] = {1086	[RK3366_PD_PERI]	= DOMAIN_RK3368("peri",   BIT(10), BIT(10), BIT(6), true),1087	[RK3366_PD_VIO]		= DOMAIN_RK3368("vio",    BIT(14), BIT(14), BIT(8), false),1088	[RK3366_PD_VIDEO]	= DOMAIN_RK3368("video",  BIT(13), BIT(13), BIT(7), false),1089	[RK3366_PD_RKVDEC]	= DOMAIN_RK3368("vdec",   BIT(11), BIT(11), BIT(7), false),1090	[RK3366_PD_WIFIBT]	= DOMAIN_RK3368("wifibt", BIT(8),  BIT(8),  BIT(9), false),1091	[RK3366_PD_VPU]		= DOMAIN_RK3368("vpu",    BIT(12), BIT(12), BIT(7), false),1092	[RK3366_PD_GPU]		= DOMAIN_RK3368("gpu",    BIT(15), BIT(15), BIT(2), false),1093};1094 1095static const struct rockchip_domain_info rk3368_pm_domains[] = {1096	[RK3368_PD_PERI]	= DOMAIN_RK3368("peri",  BIT(13), BIT(12), BIT(6), true),1097	[RK3368_PD_VIO]		= DOMAIN_RK3368("vio",   BIT(15), BIT(14), BIT(8), false),1098	[RK3368_PD_VIDEO]	= DOMAIN_RK3368("video", BIT(14), BIT(13), BIT(7), false),1099	[RK3368_PD_GPU_0]	= DOMAIN_RK3368("gpu_0", BIT(16), BIT(15), BIT(2), false),1100	[RK3368_PD_GPU_1]	= DOMAIN_RK3368("gpu_1", BIT(17), BIT(16), BIT(2), false),1101};1102 1103static const struct rockchip_domain_info rk3399_pm_domains[] = {1104	[RK3399_PD_TCPD0]	= DOMAIN_RK3399("tcpd0",     BIT(8),  BIT(8),  0,       false),1105	[RK3399_PD_TCPD1]	= DOMAIN_RK3399("tcpd1",     BIT(9),  BIT(9),  0,       false),1106	[RK3399_PD_CCI]		= DOMAIN_RK3399("cci",       BIT(10), BIT(10), 0,       true),1107	[RK3399_PD_CCI0]	= DOMAIN_RK3399("cci0",      0,       0,       BIT(15), true),1108	[RK3399_PD_CCI1]	= DOMAIN_RK3399("cci1",      0,       0,       BIT(16), true),1109	[RK3399_PD_PERILP]	= DOMAIN_RK3399("perilp",    BIT(11), BIT(11), BIT(1),  true),1110	[RK3399_PD_PERIHP]	= DOMAIN_RK3399("perihp",    BIT(12), BIT(12), BIT(2),  true),1111	[RK3399_PD_CENTER]	= DOMAIN_RK3399("center",    BIT(13), BIT(13), BIT(14), true),1112	[RK3399_PD_VIO]		= DOMAIN_RK3399("vio",       BIT(14), BIT(14), BIT(17), false),1113	[RK3399_PD_GPU]		= DOMAIN_RK3399("gpu",       BIT(15), BIT(15), BIT(0),  false),1114	[RK3399_PD_VCODEC]	= DOMAIN_RK3399("vcodec",    BIT(16), BIT(16), BIT(3),  false),1115	[RK3399_PD_VDU]		= DOMAIN_RK3399("vdu",       BIT(17), BIT(17), BIT(4),  false),1116	[RK3399_PD_RGA]		= DOMAIN_RK3399("rga",       BIT(18), BIT(18), BIT(5),  false),1117	[RK3399_PD_IEP]		= DOMAIN_RK3399("iep",       BIT(19), BIT(19), BIT(6),  false),1118	[RK3399_PD_VO]		= DOMAIN_RK3399("vo",        BIT(20), BIT(20), 0,       false),1119	[RK3399_PD_VOPB]	= DOMAIN_RK3399("vopb",      0,       0,       BIT(7),  false),1120	[RK3399_PD_VOPL]	= DOMAIN_RK3399("vopl",      0,       0,       BIT(8),  false),1121	[RK3399_PD_ISP0]	= DOMAIN_RK3399("isp0",      BIT(22), BIT(22), BIT(9),  false),1122	[RK3399_PD_ISP1]	= DOMAIN_RK3399("isp1",      BIT(23), BIT(23), BIT(10), false),1123	[RK3399_PD_HDCP]	= DOMAIN_RK3399("hdcp",      BIT(24), BIT(24), BIT(11), false),1124	[RK3399_PD_GMAC]	= DOMAIN_RK3399("gmac",      BIT(25), BIT(25), BIT(23), true),1125	[RK3399_PD_EMMC]	= DOMAIN_RK3399("emmc",      BIT(26), BIT(26), BIT(24), true),1126	[RK3399_PD_USB3]	= DOMAIN_RK3399("usb3",      BIT(27), BIT(27), BIT(12), true),1127	[RK3399_PD_EDP]		= DOMAIN_RK3399("edp",       BIT(28), BIT(28), BIT(22), false),1128	[RK3399_PD_GIC]		= DOMAIN_RK3399("gic",       BIT(29), BIT(29), BIT(27), true),1129	[RK3399_PD_SD]		= DOMAIN_RK3399("sd",        BIT(30), BIT(30), BIT(28), true),1130	[RK3399_PD_SDIOAUDIO]	= DOMAIN_RK3399("sdioaudio", BIT(31), BIT(31), BIT(29), true),1131};1132 1133static const struct rockchip_domain_info rk3568_pm_domains[] = {1134	[RK3568_PD_NPU]		= DOMAIN_RK3568("npu",  BIT(1), BIT(2),  false),1135	[RK3568_PD_GPU]		= DOMAIN_RK3568("gpu",  BIT(0), BIT(1),  false),1136	[RK3568_PD_VI]		= DOMAIN_RK3568("vi",   BIT(6), BIT(3),  false),1137	[RK3568_PD_VO]		= DOMAIN_RK3568("vo",   BIT(7), BIT(4),  false),1138	[RK3568_PD_RGA]		= DOMAIN_RK3568("rga",  BIT(5), BIT(5),  false),1139	[RK3568_PD_VPU]		= DOMAIN_RK3568("vpu",  BIT(2), BIT(6),  false),1140	[RK3568_PD_RKVDEC]	= DOMAIN_RK3568("vdec", BIT(4), BIT(8),  false),1141	[RK3568_PD_RKVENC]	= DOMAIN_RK3568("venc", BIT(3), BIT(7),  false),1142	[RK3568_PD_PIPE]	= DOMAIN_RK3568("pipe", BIT(8), BIT(11), false),1143};1144 1145static const struct rockchip_domain_info rk3576_pm_domains[] = {1146	[RK3576_PD_NPU]		= DOMAIN_RK3576("npu",    0x0, BIT(0),  BIT(0), 0,       0x0, 0,       0,       0,       false),1147	[RK3576_PD_NVM]		= DOMAIN_RK3576("nvm",    0x0, BIT(6),  0,      BIT(6),  0x4, BIT(2),  BIT(18), BIT(2),  false),1148	[RK3576_PD_SDGMAC]	= DOMAIN_RK3576("sdgmac", 0x0, BIT(7),  0,      BIT(7),  0x4, BIT(1),  BIT(17), 0x6,     false),1149	[RK3576_PD_AUDIO]	= DOMAIN_RK3576("audio",  0x0, BIT(8),  0,      BIT(8),  0x4, BIT(0),  BIT(16), BIT(0),  false),1150	[RK3576_PD_PHP]		= DOMAIN_RK3576("php",    0x0, BIT(9),  0,      BIT(9),  0x0, BIT(15), BIT(15), BIT(15), false),1151	[RK3576_PD_SUBPHP]	= DOMAIN_RK3576("subphp", 0x0, BIT(10), 0,      BIT(10), 0x0, 0,       0,       0,       false),1152	[RK3576_PD_VOP]		= DOMAIN_RK3576("vop",    0x0, BIT(11), 0,      BIT(11), 0x0, 0x6000,  0x6000,  0x6000,  false),1153	[RK3576_PD_VO1]		= DOMAIN_RK3576("vo1",    0x0, BIT(14), 0,      BIT(14), 0x0, BIT(12), BIT(12), 0x7000,  false),1154	[RK3576_PD_VO0]		= DOMAIN_RK3576("vo0",    0x0, BIT(15), 0,      BIT(15), 0x0, BIT(11), BIT(11), 0x6800,  false),1155	[RK3576_PD_USB]		= DOMAIN_RK3576("usb",    0x4, BIT(0),  0,      BIT(16), 0x0, BIT(10), BIT(10), 0x6400,  true),1156	[RK3576_PD_VI]		= DOMAIN_RK3576("vi",     0x4, BIT(1),  0,      BIT(17), 0x0, BIT(9),  BIT(9),  BIT(9),  false),1157	[RK3576_PD_VEPU0]	= DOMAIN_RK3576("vepu0",  0x4, BIT(2),  0,      BIT(18), 0x0, BIT(7),  BIT(7),  0x280,   false),1158	[RK3576_PD_VEPU1]	= DOMAIN_RK3576("vepu1",  0x4, BIT(3),  0,      BIT(19), 0x0, BIT(8),  BIT(8),  BIT(8),  false),1159	[RK3576_PD_VDEC]	= DOMAIN_RK3576("vdec",   0x4, BIT(4),  0,      BIT(20), 0x0, BIT(6),  BIT(6),  BIT(6),  false),1160	[RK3576_PD_VPU]		= DOMAIN_RK3576("vpu",    0x4, BIT(5),  0,      BIT(21), 0x0, BIT(5),  BIT(5),  BIT(5),  false),1161	[RK3576_PD_NPUTOP]	= DOMAIN_RK3576("nputop", 0x4, BIT(6),  0,      BIT(22), 0x0, 0x18,    0x18,    0x18,    false),1162	[RK3576_PD_NPU0]	= DOMAIN_RK3576("npu0",   0x4, BIT(7),  0,      BIT(23), 0x0, BIT(1),  BIT(1),  0x1a,    false),1163	[RK3576_PD_NPU1]	= DOMAIN_RK3576("npu1",   0x4, BIT(8),  0,      BIT(24), 0x0, BIT(2),  BIT(2),  0x1c,    false),1164	[RK3576_PD_GPU]		= DOMAIN_RK3576("gpu",    0x4, BIT(9),  0,      BIT(25), 0x0, BIT(0),  BIT(0),  BIT(0),  false),1165};1166 1167static const struct rockchip_domain_info rk3588_pm_domains[] = {1168	[RK3588_PD_GPU]		= DOMAIN_RK3588("gpu",     0x0, BIT(0),  0,       0x0, 0,       BIT(1),  0x0, BIT(0),  BIT(0),  false),1169	[RK3588_PD_NPU]		= DOMAIN_RK3588("npu",     0x0, BIT(1),  BIT(1),  0x0, 0,       0,       0x0, 0,       0,       false),1170	[RK3588_PD_VCODEC]	= DOMAIN_RK3588("vcodec",  0x0, BIT(2),  BIT(2),  0x0, 0,       0,       0x0, 0,       0,       false),1171	[RK3588_PD_NPUTOP]	= DOMAIN_RK3588("nputop",  0x0, BIT(3),  0,       0x0, BIT(11), BIT(2),  0x0, BIT(1),  BIT(1),  false),1172	[RK3588_PD_NPU1]	= DOMAIN_RK3588("npu1",    0x0, BIT(4),  0,       0x0, BIT(12), BIT(3),  0x0, BIT(2),  BIT(2),  false),1173	[RK3588_PD_NPU2]	= DOMAIN_RK3588("npu2",    0x0, BIT(5),  0,       0x0, BIT(13), BIT(4),  0x0, BIT(3),  BIT(3),  false),1174	[RK3588_PD_VENC0]	= DOMAIN_RK3588("venc0",   0x0, BIT(6),  0,       0x0, BIT(14), BIT(5),  0x0, BIT(4),  BIT(4),  false),1175	[RK3588_PD_VENC1]	= DOMAIN_RK3588("venc1",   0x0, BIT(7),  0,       0x0, BIT(15), BIT(6),  0x0, BIT(5),  BIT(5),  false),1176	[RK3588_PD_RKVDEC0]	= DOMAIN_RK3588("rkvdec0", 0x0, BIT(8),  0,       0x0, BIT(16), BIT(7),  0x0, BIT(6),  BIT(6),  false),1177	[RK3588_PD_RKVDEC1]	= DOMAIN_RK3588("rkvdec1", 0x0, BIT(9),  0,       0x0, BIT(17), BIT(8),  0x0, BIT(7),  BIT(7),  false),1178	[RK3588_PD_VDPU]	= DOMAIN_RK3588("vdpu",    0x0, BIT(10), 0,       0x0, BIT(18), BIT(9),  0x0, BIT(8),  BIT(8),  false),1179	[RK3588_PD_RGA30]	= DOMAIN_RK3588("rga30",   0x0, BIT(11), 0,       0x0, BIT(19), BIT(10), 0x0, 0,       0,       false),1180	[RK3588_PD_AV1]		= DOMAIN_RK3588("av1",     0x0, BIT(12), 0,       0x0, BIT(20), BIT(11), 0x0, BIT(9),  BIT(9),  false),1181	[RK3588_PD_VI]		= DOMAIN_RK3588("vi",      0x0, BIT(13), 0,       0x0, BIT(21), BIT(12), 0x0, BIT(10), BIT(10), false),1182	[RK3588_PD_FEC]		= DOMAIN_RK3588("fec",     0x0, BIT(14), 0,       0x0, BIT(22), BIT(13), 0x0, 0,       0,       false),1183	[RK3588_PD_ISP1]	= DOMAIN_RK3588("isp1",    0x0, BIT(15), 0,       0x0, BIT(23), BIT(14), 0x0, BIT(11), BIT(11), false),1184	[RK3588_PD_RGA31]	= DOMAIN_RK3588("rga31",   0x4, BIT(0),  0,       0x0, BIT(24), BIT(15), 0x0, BIT(12), BIT(12), false),1185	[RK3588_PD_VOP]		= DOMAIN_RK3588("vop",     0x4, BIT(1),  0,       0x0, BIT(25), BIT(16), 0x0, BIT(13) | BIT(14), BIT(13) | BIT(14), false),1186	[RK3588_PD_VO0]		= DOMAIN_RK3588("vo0",     0x4, BIT(2),  0,       0x0, BIT(26), BIT(17), 0x0, BIT(15), BIT(15), false),1187	[RK3588_PD_VO1]		= DOMAIN_RK3588("vo1",     0x4, BIT(3),  0,       0x0, BIT(27), BIT(18), 0x4, BIT(0),  BIT(16), false),1188	[RK3588_PD_AUDIO]	= DOMAIN_RK3588("audio",   0x4, BIT(4),  0,       0x0, BIT(28), BIT(19), 0x4, BIT(1),  BIT(17), false),1189	[RK3588_PD_PHP]		= DOMAIN_RK3588("php",     0x4, BIT(5),  0,       0x0, BIT(29), BIT(20), 0x4, BIT(5),  BIT(21), false),1190	[RK3588_PD_GMAC]	= DOMAIN_RK3588("gmac",    0x4, BIT(6),  0,       0x0, BIT(30), BIT(21), 0x0, 0,       0,       false),1191	[RK3588_PD_PCIE]	= DOMAIN_RK3588("pcie",    0x4, BIT(7),  0,       0x0, BIT(31), BIT(22), 0x0, 0,       0,       true),1192	[RK3588_PD_NVM]		= DOMAIN_RK3588("nvm",     0x4, BIT(8),  BIT(24), 0x4, 0,       0,       0x4, BIT(2),  BIT(18), false),1193	[RK3588_PD_NVM0]	= DOMAIN_RK3588("nvm0",    0x4, BIT(9),  0,       0x4, BIT(1),  BIT(23), 0x0, 0,       0,       false),1194	[RK3588_PD_SDIO]	= DOMAIN_RK3588("sdio",    0x4, BIT(10), 0,       0x4, BIT(2),  BIT(24), 0x4, BIT(3),  BIT(19), false),1195	[RK3588_PD_USB]		= DOMAIN_RK3588("usb",     0x4, BIT(11), 0,       0x4, BIT(3),  BIT(25), 0x4, BIT(4),  BIT(20), true),1196	[RK3588_PD_SDMMC]	= DOMAIN_RK3588("sdmmc",   0x4, BIT(13), 0,       0x4, BIT(5),  BIT(26), 0x0, 0,       0,       false),1197};1198 1199static const struct rockchip_pmu_info px30_pmu = {1200	.pwr_offset = 0x18,1201	.status_offset = 0x20,1202	.req_offset = 0x64,1203	.idle_offset = 0x6c,1204	.ack_offset = 0x6c,1205 1206	.num_domains = ARRAY_SIZE(px30_pm_domains),1207	.domain_info = px30_pm_domains,1208};1209 1210static const struct rockchip_pmu_info rk3036_pmu = {1211	.req_offset = 0x148,1212	.idle_offset = 0x14c,1213	.ack_offset = 0x14c,1214 1215	.num_domains = ARRAY_SIZE(rk3036_pm_domains),1216	.domain_info = rk3036_pm_domains,1217};1218 1219static const struct rockchip_pmu_info rk3066_pmu = {1220	.pwr_offset = 0x08,1221	.status_offset = 0x0c,1222	.req_offset = 0x38, /* PMU_MISC_CON1 */1223	.idle_offset = 0x0c,1224	.ack_offset = 0x0c,1225 1226	.num_domains = ARRAY_SIZE(rk3066_pm_domains),1227	.domain_info = rk3066_pm_domains,1228};1229 1230static const struct rockchip_pmu_info rk3128_pmu = {1231	.pwr_offset = 0x04,1232	.status_offset = 0x08,1233	.req_offset = 0x0c,1234	.idle_offset = 0x10,1235	.ack_offset = 0x10,1236 1237	.num_domains = ARRAY_SIZE(rk3128_pm_domains),1238	.domain_info = rk3128_pm_domains,1239};1240 1241static const struct rockchip_pmu_info rk3188_pmu = {1242	.pwr_offset = 0x08,1243	.status_offset = 0x0c,1244	.req_offset = 0x38, /* PMU_MISC_CON1 */1245	.idle_offset = 0x0c,1246	.ack_offset = 0x0c,1247 1248	.num_domains = ARRAY_SIZE(rk3188_pm_domains),1249	.domain_info = rk3188_pm_domains,1250};1251 1252static const struct rockchip_pmu_info rk3228_pmu = {1253	.req_offset = 0x40c,1254	.idle_offset = 0x488,1255	.ack_offset = 0x488,1256 1257	.num_domains = ARRAY_SIZE(rk3228_pm_domains),1258	.domain_info = rk3228_pm_domains,1259};1260 1261static const struct rockchip_pmu_info rk3288_pmu = {1262	.pwr_offset = 0x08,1263	.status_offset = 0x0c,1264	.req_offset = 0x10,1265	.idle_offset = 0x14,1266	.ack_offset = 0x14,1267 1268	.core_pwrcnt_offset = 0x34,1269	.gpu_pwrcnt_offset = 0x3c,1270 1271	.core_power_transition_time = 24, /* 1us */1272	.gpu_power_transition_time = 24, /* 1us */1273 1274	.num_domains = ARRAY_SIZE(rk3288_pm_domains),1275	.domain_info = rk3288_pm_domains,1276};1277 1278static const struct rockchip_pmu_info rk3328_pmu = {1279	.req_offset = 0x414,1280	.idle_offset = 0x484,1281	.ack_offset = 0x484,1282 1283	.num_domains = ARRAY_SIZE(rk3328_pm_domains),1284	.domain_info = rk3328_pm_domains,1285};1286 1287static const struct rockchip_pmu_info rk3366_pmu = {1288	.pwr_offset = 0x0c,1289	.status_offset = 0x10,1290	.req_offset = 0x3c,1291	.idle_offset = 0x40,1292	.ack_offset = 0x40,1293 1294	.core_pwrcnt_offset = 0x48,1295	.gpu_pwrcnt_offset = 0x50,1296 1297	.core_power_transition_time = 24,1298	.gpu_power_transition_time = 24,1299 1300	.num_domains = ARRAY_SIZE(rk3366_pm_domains),1301	.domain_info = rk3366_pm_domains,1302};1303 1304static const struct rockchip_pmu_info rk3368_pmu = {1305	.pwr_offset = 0x0c,1306	.status_offset = 0x10,1307	.req_offset = 0x3c,1308	.idle_offset = 0x40,1309	.ack_offset = 0x40,1310 1311	.core_pwrcnt_offset = 0x48,1312	.gpu_pwrcnt_offset = 0x50,1313 1314	.core_power_transition_time = 24,1315	.gpu_power_transition_time = 24,1316 1317	.num_domains = ARRAY_SIZE(rk3368_pm_domains),1318	.domain_info = rk3368_pm_domains,1319};1320 1321static const struct rockchip_pmu_info rk3399_pmu = {1322	.pwr_offset = 0x14,1323	.status_offset = 0x18,1324	.req_offset = 0x60,1325	.idle_offset = 0x64,1326	.ack_offset = 0x68,1327 1328	/* ARM Trusted Firmware manages power transition times */1329 1330	.num_domains = ARRAY_SIZE(rk3399_pm_domains),1331	.domain_info = rk3399_pm_domains,1332};1333 1334static const struct rockchip_pmu_info rk3568_pmu = {1335	.pwr_offset = 0xa0,1336	.status_offset = 0x98,1337	.req_offset = 0x50,1338	.idle_offset = 0x68,1339	.ack_offset = 0x60,1340 1341	.num_domains = ARRAY_SIZE(rk3568_pm_domains),1342	.domain_info = rk3568_pm_domains,1343};1344 1345static const struct rockchip_pmu_info rk3576_pmu = {1346	.pwr_offset = 0x210,1347	.status_offset = 0x230,1348	.chain_status_offset = 0x248,1349	.mem_status_offset = 0x250,1350	.mem_pwr_offset = 0x300,1351	.req_offset = 0x110,1352	.idle_offset = 0x128,1353	.ack_offset = 0x120,1354	.repair_status_offset = 0x570,1355	.clk_ungate_offset = 0x140,1356 1357	.num_domains = ARRAY_SIZE(rk3576_pm_domains),1358	.domain_info = rk3576_pm_domains,1359};1360 1361static const struct rockchip_pmu_info rk3588_pmu = {1362	.pwr_offset = 0x14c,1363	.status_offset = 0x180,1364	.req_offset = 0x10c,1365	.idle_offset = 0x120,1366	.ack_offset = 0x118,1367	.mem_pwr_offset = 0x1a0,1368	.chain_status_offset = 0x1f0,1369	.mem_status_offset = 0x1f8,1370	.repair_status_offset = 0x290,1371 1372	.num_domains = ARRAY_SIZE(rk3588_pm_domains),1373	.domain_info = rk3588_pm_domains,1374};1375 1376static const struct rockchip_pmu_info rv1126_pmu = {1377	.pwr_offset = 0x110,1378	.status_offset = 0x108,1379	.req_offset = 0xc0,1380	.idle_offset = 0xd8,1381	.ack_offset = 0xd0,1382 1383	.num_domains = ARRAY_SIZE(rv1126_pm_domains),1384	.domain_info = rv1126_pm_domains,1385};1386 1387static const struct of_device_id rockchip_pm_domain_dt_match[] = {1388	{1389		.compatible = "rockchip,px30-power-controller",1390		.data = (void *)&px30_pmu,1391	},1392	{1393		.compatible = "rockchip,rk3036-power-controller",1394		.data = (void *)&rk3036_pmu,1395	},1396	{1397		.compatible = "rockchip,rk3066-power-controller",1398		.data = (void *)&rk3066_pmu,1399	},1400	{1401		.compatible = "rockchip,rk3128-power-controller",1402		.data = (void *)&rk3128_pmu,1403	},1404	{1405		.compatible = "rockchip,rk3188-power-controller",1406		.data = (void *)&rk3188_pmu,1407	},1408	{1409		.compatible = "rockchip,rk3228-power-controller",1410		.data = (void *)&rk3228_pmu,1411	},1412	{1413		.compatible = "rockchip,rk3288-power-controller",1414		.data = (void *)&rk3288_pmu,1415	},1416	{1417		.compatible = "rockchip,rk3328-power-controller",1418		.data = (void *)&rk3328_pmu,1419	},1420	{1421		.compatible = "rockchip,rk3366-power-controller",1422		.data = (void *)&rk3366_pmu,1423	},1424	{1425		.compatible = "rockchip,rk3368-power-controller",1426		.data = (void *)&rk3368_pmu,1427	},1428	{1429		.compatible = "rockchip,rk3399-power-controller",1430		.data = (void *)&rk3399_pmu,1431	},1432	{1433		.compatible = "rockchip,rk3568-power-controller",1434		.data = (void *)&rk3568_pmu,1435	},1436	{1437		.compatible = "rockchip,rk3576-power-controller",1438		.data = (void *)&rk3576_pmu,1439	},1440	{1441		.compatible = "rockchip,rk3588-power-controller",1442		.data = (void *)&rk3588_pmu,1443	},1444	{1445		.compatible = "rockchip,rv1126-power-controller",1446		.data = (void *)&rv1126_pmu,1447	},1448	{ /* sentinel */ },1449};1450 1451static struct platform_driver rockchip_pm_domain_driver = {1452	.probe = rockchip_pm_domain_probe,1453	.driver = {1454		.name   = "rockchip-pm-domain",1455		.of_match_table = rockchip_pm_domain_dt_match,1456		/*1457		 * We can't forcibly eject devices from the power1458		 * domain, so we can't really remove power domains1459		 * once they were added.1460		 */1461		.suppress_bind_attrs = true,1462	},1463};1464 1465static int __init rockchip_pm_domain_drv_register(void)1466{1467	return platform_driver_register(&rockchip_pm_domain_driver);1468}1469postcore_initcall(rockchip_pm_domain_drv_register);1470