162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * OMAP2+ PRM driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
662306a36Sopenharmony_ci *	Tero Kristo <t-kristo@ti.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/iopoll.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/pm_clock.h>
1862306a36Sopenharmony_ci#include <linux/pm_domain.h>
1962306a36Sopenharmony_ci#include <linux/reset-controller.h>
2062306a36Sopenharmony_ci#include <linux/delay.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/platform_data/ti-prm.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cienum omap_prm_domain_mode {
2562306a36Sopenharmony_ci	OMAP_PRMD_OFF,
2662306a36Sopenharmony_ci	OMAP_PRMD_RETENTION,
2762306a36Sopenharmony_ci	OMAP_PRMD_ON_INACTIVE,
2862306a36Sopenharmony_ci	OMAP_PRMD_ON_ACTIVE,
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct omap_prm_domain_map {
3262306a36Sopenharmony_ci	unsigned int usable_modes;	/* Mask of hardware supported modes */
3362306a36Sopenharmony_ci	unsigned long statechange:1;	/* Optional low-power state change */
3462306a36Sopenharmony_ci	unsigned long logicretstate:1;	/* Optional logic off mode */
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistruct omap_prm_domain {
3862306a36Sopenharmony_ci	struct device *dev;
3962306a36Sopenharmony_ci	struct omap_prm *prm;
4062306a36Sopenharmony_ci	struct generic_pm_domain pd;
4162306a36Sopenharmony_ci	u16 pwrstctrl;
4262306a36Sopenharmony_ci	u16 pwrstst;
4362306a36Sopenharmony_ci	const struct omap_prm_domain_map *cap;
4462306a36Sopenharmony_ci	u32 pwrstctrl_saved;
4562306a36Sopenharmony_ci	unsigned int uses_pm_clk:1;
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistruct omap_rst_map {
4962306a36Sopenharmony_ci	s8 rst;
5062306a36Sopenharmony_ci	s8 st;
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct omap_prm_data {
5462306a36Sopenharmony_ci	u32 base;
5562306a36Sopenharmony_ci	const char *name;
5662306a36Sopenharmony_ci	const char *clkdm_name;
5762306a36Sopenharmony_ci	u16 pwrstctrl;
5862306a36Sopenharmony_ci	u16 pwrstst;
5962306a36Sopenharmony_ci	const struct omap_prm_domain_map *dmap;
6062306a36Sopenharmony_ci	u16 rstctrl;
6162306a36Sopenharmony_ci	u16 rstst;
6262306a36Sopenharmony_ci	const struct omap_rst_map *rstmap;
6362306a36Sopenharmony_ci	u8 flags;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistruct omap_prm {
6762306a36Sopenharmony_ci	const struct omap_prm_data *data;
6862306a36Sopenharmony_ci	void __iomem *base;
6962306a36Sopenharmony_ci	struct omap_prm_domain *prmd;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct omap_reset_data {
7362306a36Sopenharmony_ci	struct reset_controller_dev rcdev;
7462306a36Sopenharmony_ci	struct omap_prm *prm;
7562306a36Sopenharmony_ci	u32 mask;
7662306a36Sopenharmony_ci	spinlock_t lock;
7762306a36Sopenharmony_ci	struct clockdomain *clkdm;
7862306a36Sopenharmony_ci	struct device *dev;
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd)
8262306a36Sopenharmony_ci#define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define OMAP_MAX_RESETS		8
8562306a36Sopenharmony_ci#define OMAP_RESET_MAX_WAIT	10000
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#define OMAP_PRM_HAS_RSTCTRL	BIT(0)
8862306a36Sopenharmony_ci#define OMAP_PRM_HAS_RSTST	BIT(1)
8962306a36Sopenharmony_ci#define OMAP_PRM_HAS_NO_CLKDM	BIT(2)
9062306a36Sopenharmony_ci#define OMAP_PRM_RET_WHEN_IDLE	BIT(3)
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define OMAP_PRM_HAS_RESETS	(OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define PRM_STATE_MAX_WAIT	10000
9562306a36Sopenharmony_ci#define PRM_LOGICRETSTATE	BIT(2)
9662306a36Sopenharmony_ci#define PRM_LOWPOWERSTATECHANGE	BIT(4)
9762306a36Sopenharmony_ci#define PRM_POWERSTATE_MASK	OMAP_PRMD_ON_ACTIVE
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define PRM_ST_INTRANSITION	BIT(20)
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_all = {
10262306a36Sopenharmony_ci	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
10362306a36Sopenharmony_ci			BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF),
10462306a36Sopenharmony_ci	.statechange = 1,
10562306a36Sopenharmony_ci	.logicretstate = 1,
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_noinact = {
10962306a36Sopenharmony_ci	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) |
11062306a36Sopenharmony_ci			BIT(OMAP_PRMD_OFF),
11162306a36Sopenharmony_ci	.statechange = 1,
11262306a36Sopenharmony_ci	.logicretstate = 1,
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_nooff = {
11662306a36Sopenharmony_ci	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
11762306a36Sopenharmony_ci			BIT(OMAP_PRMD_RETENTION),
11862306a36Sopenharmony_ci	.statechange = 1,
11962306a36Sopenharmony_ci	.logicretstate = 1,
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_onoff_noauto = {
12362306a36Sopenharmony_ci	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF),
12462306a36Sopenharmony_ci	.statechange = 1,
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_alwon = {
12862306a36Sopenharmony_ci	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE),
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_reton = {
13262306a36Sopenharmony_ci	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION),
13362306a36Sopenharmony_ci	.statechange = 1,
13462306a36Sopenharmony_ci	.logicretstate = 1,
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic const struct omap_rst_map rst_map_0[] = {
13862306a36Sopenharmony_ci	{ .rst = 0, .st = 0 },
13962306a36Sopenharmony_ci	{ .rst = -1 },
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic const struct omap_rst_map rst_map_01[] = {
14362306a36Sopenharmony_ci	{ .rst = 0, .st = 0 },
14462306a36Sopenharmony_ci	{ .rst = 1, .st = 1 },
14562306a36Sopenharmony_ci	{ .rst = -1 },
14662306a36Sopenharmony_ci};
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic const struct omap_rst_map rst_map_012[] = {
14962306a36Sopenharmony_ci	{ .rst = 0, .st = 0 },
15062306a36Sopenharmony_ci	{ .rst = 1, .st = 1 },
15162306a36Sopenharmony_ci	{ .rst = 2, .st = 2 },
15262306a36Sopenharmony_ci	{ .rst = -1 },
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic const struct omap_prm_data omap4_prm_data[] = {
15662306a36Sopenharmony_ci	{
15762306a36Sopenharmony_ci		.name = "mpu", .base = 0x4a306300,
15862306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
15962306a36Sopenharmony_ci	},
16062306a36Sopenharmony_ci	{
16162306a36Sopenharmony_ci		.name = "tesla", .base = 0x4a306400,
16262306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
16362306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
16462306a36Sopenharmony_ci	},
16562306a36Sopenharmony_ci	{
16662306a36Sopenharmony_ci		.name = "abe", .base = 0x4a306500,
16762306a36Sopenharmony_ci		.pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all,
16862306a36Sopenharmony_ci	},
16962306a36Sopenharmony_ci	{
17062306a36Sopenharmony_ci		.name = "always_on_core", .base = 0x4a306600,
17162306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
17262306a36Sopenharmony_ci	},
17362306a36Sopenharmony_ci	{
17462306a36Sopenharmony_ci		.name = "core", .base = 0x4a306700,
17562306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
17662306a36Sopenharmony_ci		.rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati",
17762306a36Sopenharmony_ci		.rstmap = rst_map_012,
17862306a36Sopenharmony_ci		.flags = OMAP_PRM_RET_WHEN_IDLE,
17962306a36Sopenharmony_ci	},
18062306a36Sopenharmony_ci	{
18162306a36Sopenharmony_ci		.name = "ivahd", .base = 0x4a306f00,
18262306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
18362306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
18462306a36Sopenharmony_ci	},
18562306a36Sopenharmony_ci	{
18662306a36Sopenharmony_ci		.name = "cam", .base = 0x4a307000,
18762306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
18862306a36Sopenharmony_ci	},
18962306a36Sopenharmony_ci	{
19062306a36Sopenharmony_ci		.name = "dss", .base = 0x4a307100,
19162306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact
19262306a36Sopenharmony_ci	},
19362306a36Sopenharmony_ci	{
19462306a36Sopenharmony_ci		.name = "gfx", .base = 0x4a307200,
19562306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
19662306a36Sopenharmony_ci	},
19762306a36Sopenharmony_ci	{
19862306a36Sopenharmony_ci		.name = "l3init", .base = 0x4a307300,
19962306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton
20062306a36Sopenharmony_ci	},
20162306a36Sopenharmony_ci	{
20262306a36Sopenharmony_ci		.name = "l4per", .base = 0x4a307400,
20362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
20462306a36Sopenharmony_ci		.flags = OMAP_PRM_RET_WHEN_IDLE,
20562306a36Sopenharmony_ci	},
20662306a36Sopenharmony_ci	{
20762306a36Sopenharmony_ci		.name = "cefuse", .base = 0x4a307600,
20862306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
20962306a36Sopenharmony_ci	},
21062306a36Sopenharmony_ci	{
21162306a36Sopenharmony_ci		.name = "wkup", .base = 0x4a307700,
21262306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
21362306a36Sopenharmony_ci	},
21462306a36Sopenharmony_ci	{
21562306a36Sopenharmony_ci		.name = "emu", .base = 0x4a307900,
21662306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
21762306a36Sopenharmony_ci	},
21862306a36Sopenharmony_ci	{
21962306a36Sopenharmony_ci		.name = "device", .base = 0x4a307b00,
22062306a36Sopenharmony_ci		.rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01,
22162306a36Sopenharmony_ci		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
22262306a36Sopenharmony_ci	},
22362306a36Sopenharmony_ci	{ },
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic const struct omap_prm_data omap5_prm_data[] = {
22762306a36Sopenharmony_ci	{
22862306a36Sopenharmony_ci		.name = "mpu", .base = 0x4ae06300,
22962306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
23062306a36Sopenharmony_ci	},
23162306a36Sopenharmony_ci	{
23262306a36Sopenharmony_ci		.name = "dsp", .base = 0x4ae06400,
23362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
23462306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
23562306a36Sopenharmony_ci	},
23662306a36Sopenharmony_ci	{
23762306a36Sopenharmony_ci		.name = "abe", .base = 0x4ae06500,
23862306a36Sopenharmony_ci		.pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff,
23962306a36Sopenharmony_ci	},
24062306a36Sopenharmony_ci	{
24162306a36Sopenharmony_ci		.name = "coreaon", .base = 0x4ae06600,
24262306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
24362306a36Sopenharmony_ci	},
24462306a36Sopenharmony_ci	{
24562306a36Sopenharmony_ci		.name = "core", .base = 0x4ae06700,
24662306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
24762306a36Sopenharmony_ci		.rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu",
24862306a36Sopenharmony_ci		.rstmap = rst_map_012
24962306a36Sopenharmony_ci	},
25062306a36Sopenharmony_ci	{
25162306a36Sopenharmony_ci		.name = "iva", .base = 0x4ae07200,
25262306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
25362306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
25462306a36Sopenharmony_ci	},
25562306a36Sopenharmony_ci	{
25662306a36Sopenharmony_ci		.name = "cam", .base = 0x4ae07300,
25762306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
25862306a36Sopenharmony_ci	},
25962306a36Sopenharmony_ci	{
26062306a36Sopenharmony_ci		.name = "dss", .base = 0x4ae07400,
26162306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact
26262306a36Sopenharmony_ci	},
26362306a36Sopenharmony_ci	{
26462306a36Sopenharmony_ci		.name = "gpu", .base = 0x4ae07500,
26562306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
26662306a36Sopenharmony_ci	},
26762306a36Sopenharmony_ci	{
26862306a36Sopenharmony_ci		.name = "l3init", .base = 0x4ae07600,
26962306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton
27062306a36Sopenharmony_ci	},
27162306a36Sopenharmony_ci	{
27262306a36Sopenharmony_ci		.name = "custefuse", .base = 0x4ae07700,
27362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
27462306a36Sopenharmony_ci	},
27562306a36Sopenharmony_ci	{
27662306a36Sopenharmony_ci		.name = "wkupaon", .base = 0x4ae07800,
27762306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
27862306a36Sopenharmony_ci	},
27962306a36Sopenharmony_ci	{
28062306a36Sopenharmony_ci		.name = "emu", .base = 0x4ae07a00,
28162306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
28262306a36Sopenharmony_ci	},
28362306a36Sopenharmony_ci	{
28462306a36Sopenharmony_ci		.name = "device", .base = 0x4ae07c00,
28562306a36Sopenharmony_ci		.rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01,
28662306a36Sopenharmony_ci		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
28762306a36Sopenharmony_ci	},
28862306a36Sopenharmony_ci	{ },
28962306a36Sopenharmony_ci};
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic const struct omap_prm_data dra7_prm_data[] = {
29262306a36Sopenharmony_ci	{
29362306a36Sopenharmony_ci		.name = "mpu", .base = 0x4ae06300,
29462306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
29562306a36Sopenharmony_ci	},
29662306a36Sopenharmony_ci	{
29762306a36Sopenharmony_ci		.name = "dsp1", .base = 0x4ae06400,
29862306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
29962306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01,
30062306a36Sopenharmony_ci	},
30162306a36Sopenharmony_ci	{
30262306a36Sopenharmony_ci		.name = "ipu", .base = 0x4ae06500,
30362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
30462306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012,
30562306a36Sopenharmony_ci		.clkdm_name = "ipu1"
30662306a36Sopenharmony_ci	},
30762306a36Sopenharmony_ci	{
30862306a36Sopenharmony_ci		.name = "coreaon", .base = 0x4ae06628,
30962306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
31062306a36Sopenharmony_ci	},
31162306a36Sopenharmony_ci	{
31262306a36Sopenharmony_ci		.name = "core", .base = 0x4ae06700,
31362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
31462306a36Sopenharmony_ci		.rstctrl = 0x210, .rstst = 0x214, .rstmap = rst_map_012,
31562306a36Sopenharmony_ci		.clkdm_name = "ipu2"
31662306a36Sopenharmony_ci	},
31762306a36Sopenharmony_ci	{
31862306a36Sopenharmony_ci		.name = "iva", .base = 0x4ae06f00,
31962306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
32062306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012,
32162306a36Sopenharmony_ci	},
32262306a36Sopenharmony_ci	{
32362306a36Sopenharmony_ci		.name = "cam", .base = 0x4ae07000,
32462306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
32562306a36Sopenharmony_ci	},
32662306a36Sopenharmony_ci	{
32762306a36Sopenharmony_ci		.name = "dss", .base = 0x4ae07100,
32862306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
32962306a36Sopenharmony_ci	},
33062306a36Sopenharmony_ci	{
33162306a36Sopenharmony_ci		.name = "gpu", .base = 0x4ae07200,
33262306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
33362306a36Sopenharmony_ci	},
33462306a36Sopenharmony_ci	{
33562306a36Sopenharmony_ci		.name = "l3init", .base = 0x4ae07300,
33662306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
33762306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01,
33862306a36Sopenharmony_ci		.clkdm_name = "pcie"
33962306a36Sopenharmony_ci	},
34062306a36Sopenharmony_ci	{
34162306a36Sopenharmony_ci		.name = "l4per", .base = 0x4ae07400,
34262306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
34362306a36Sopenharmony_ci	},
34462306a36Sopenharmony_ci	{
34562306a36Sopenharmony_ci		.name = "custefuse", .base = 0x4ae07600,
34662306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
34762306a36Sopenharmony_ci	},
34862306a36Sopenharmony_ci	{
34962306a36Sopenharmony_ci		.name = "wkupaon", .base = 0x4ae07724,
35062306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
35162306a36Sopenharmony_ci	},
35262306a36Sopenharmony_ci	{
35362306a36Sopenharmony_ci		.name = "emu", .base = 0x4ae07900,
35462306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
35562306a36Sopenharmony_ci	},
35662306a36Sopenharmony_ci	{
35762306a36Sopenharmony_ci		.name = "dsp2", .base = 0x4ae07b00,
35862306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
35962306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
36062306a36Sopenharmony_ci	},
36162306a36Sopenharmony_ci	{
36262306a36Sopenharmony_ci		.name = "eve1", .base = 0x4ae07b40,
36362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
36462306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
36562306a36Sopenharmony_ci	},
36662306a36Sopenharmony_ci	{
36762306a36Sopenharmony_ci		.name = "eve2", .base = 0x4ae07b80,
36862306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
36962306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
37062306a36Sopenharmony_ci	},
37162306a36Sopenharmony_ci	{
37262306a36Sopenharmony_ci		.name = "eve3", .base = 0x4ae07bc0,
37362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
37462306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
37562306a36Sopenharmony_ci	},
37662306a36Sopenharmony_ci	{
37762306a36Sopenharmony_ci		.name = "eve4", .base = 0x4ae07c00,
37862306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
37962306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
38062306a36Sopenharmony_ci	},
38162306a36Sopenharmony_ci	{
38262306a36Sopenharmony_ci		.name = "rtc", .base = 0x4ae07c60,
38362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
38462306a36Sopenharmony_ci	},
38562306a36Sopenharmony_ci	{
38662306a36Sopenharmony_ci		.name = "vpe", .base = 0x4ae07c80,
38762306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
38862306a36Sopenharmony_ci	},
38962306a36Sopenharmony_ci	{ },
39062306a36Sopenharmony_ci};
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic const struct omap_rst_map am3_per_rst_map[] = {
39362306a36Sopenharmony_ci	{ .rst = 1 },
39462306a36Sopenharmony_ci	{ .rst = -1 },
39562306a36Sopenharmony_ci};
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic const struct omap_rst_map am3_wkup_rst_map[] = {
39862306a36Sopenharmony_ci	{ .rst = 3, .st = 5 },
39962306a36Sopenharmony_ci	{ .rst = -1 },
40062306a36Sopenharmony_ci};
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic const struct omap_prm_data am3_prm_data[] = {
40362306a36Sopenharmony_ci	{
40462306a36Sopenharmony_ci		.name = "per", .base = 0x44e00c00,
40562306a36Sopenharmony_ci		.pwrstctrl = 0xc, .pwrstst = 0x8, .dmap = &omap_prm_noinact,
40662306a36Sopenharmony_ci		.rstctrl = 0x0, .rstmap = am3_per_rst_map,
40762306a36Sopenharmony_ci		.flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp"
40862306a36Sopenharmony_ci	},
40962306a36Sopenharmony_ci	{
41062306a36Sopenharmony_ci		.name = "wkup", .base = 0x44e00d00,
41162306a36Sopenharmony_ci		.pwrstctrl = 0x4, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
41262306a36Sopenharmony_ci		.rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map,
41362306a36Sopenharmony_ci		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
41462306a36Sopenharmony_ci	},
41562306a36Sopenharmony_ci	{
41662306a36Sopenharmony_ci		.name = "mpu", .base = 0x44e00e00,
41762306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
41862306a36Sopenharmony_ci	},
41962306a36Sopenharmony_ci	{
42062306a36Sopenharmony_ci		.name = "device", .base = 0x44e00f00,
42162306a36Sopenharmony_ci		.rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01,
42262306a36Sopenharmony_ci		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
42362306a36Sopenharmony_ci	},
42462306a36Sopenharmony_ci	{
42562306a36Sopenharmony_ci		.name = "rtc", .base = 0x44e01000,
42662306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
42762306a36Sopenharmony_ci	},
42862306a36Sopenharmony_ci	{
42962306a36Sopenharmony_ci		.name = "gfx", .base = 0x44e01100,
43062306a36Sopenharmony_ci		.pwrstctrl = 0, .pwrstst = 0x10, .dmap = &omap_prm_noinact,
43162306a36Sopenharmony_ci		.rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
43262306a36Sopenharmony_ci	},
43362306a36Sopenharmony_ci	{
43462306a36Sopenharmony_ci		.name = "cefuse", .base = 0x44e01200,
43562306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
43662306a36Sopenharmony_ci	},
43762306a36Sopenharmony_ci	{ },
43862306a36Sopenharmony_ci};
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic const struct omap_rst_map am4_per_rst_map[] = {
44162306a36Sopenharmony_ci	{ .rst = 1, .st = 0 },
44262306a36Sopenharmony_ci	{ .rst = -1 },
44362306a36Sopenharmony_ci};
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic const struct omap_rst_map am4_device_rst_map[] = {
44662306a36Sopenharmony_ci	{ .rst = 0, .st = 1 },
44762306a36Sopenharmony_ci	{ .rst = 1, .st = 0 },
44862306a36Sopenharmony_ci	{ .rst = -1 },
44962306a36Sopenharmony_ci};
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic const struct omap_prm_data am4_prm_data[] = {
45262306a36Sopenharmony_ci	{
45362306a36Sopenharmony_ci		.name = "mpu", .base = 0x44df0300,
45462306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
45562306a36Sopenharmony_ci	},
45662306a36Sopenharmony_ci	{
45762306a36Sopenharmony_ci		.name = "gfx", .base = 0x44df0400,
45862306a36Sopenharmony_ci		.pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
45962306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
46062306a36Sopenharmony_ci	},
46162306a36Sopenharmony_ci	{
46262306a36Sopenharmony_ci		.name = "rtc", .base = 0x44df0500,
46362306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
46462306a36Sopenharmony_ci	},
46562306a36Sopenharmony_ci	{
46662306a36Sopenharmony_ci		.name = "tamper", .base = 0x44df0600,
46762306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
46862306a36Sopenharmony_ci	},
46962306a36Sopenharmony_ci	{
47062306a36Sopenharmony_ci		.name = "cefuse", .base = 0x44df0700,
47162306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
47262306a36Sopenharmony_ci	},
47362306a36Sopenharmony_ci	{
47462306a36Sopenharmony_ci		.name = "per", .base = 0x44df0800,
47562306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
47662306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map,
47762306a36Sopenharmony_ci		.clkdm_name = "pruss_ocp"
47862306a36Sopenharmony_ci	},
47962306a36Sopenharmony_ci	{
48062306a36Sopenharmony_ci		.name = "wkup", .base = 0x44df2000,
48162306a36Sopenharmony_ci		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
48262306a36Sopenharmony_ci		.rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map,
48362306a36Sopenharmony_ci		.flags = OMAP_PRM_HAS_NO_CLKDM
48462306a36Sopenharmony_ci	},
48562306a36Sopenharmony_ci	{
48662306a36Sopenharmony_ci		.name = "device", .base = 0x44df4000,
48762306a36Sopenharmony_ci		.rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map,
48862306a36Sopenharmony_ci		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
48962306a36Sopenharmony_ci	},
49062306a36Sopenharmony_ci	{ },
49162306a36Sopenharmony_ci};
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic const struct of_device_id omap_prm_id_table[] = {
49462306a36Sopenharmony_ci	{ .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data },
49562306a36Sopenharmony_ci	{ .compatible = "ti,omap5-prm-inst", .data = omap5_prm_data },
49662306a36Sopenharmony_ci	{ .compatible = "ti,dra7-prm-inst", .data = dra7_prm_data },
49762306a36Sopenharmony_ci	{ .compatible = "ti,am3-prm-inst", .data = am3_prm_data },
49862306a36Sopenharmony_ci	{ .compatible = "ti,am4-prm-inst", .data = am4_prm_data },
49962306a36Sopenharmony_ci	{ },
50062306a36Sopenharmony_ci};
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci#ifdef DEBUG
50362306a36Sopenharmony_cistatic void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
50462306a36Sopenharmony_ci				       const char *desc)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	dev_dbg(prmd->dev, "%s %s: %08x/%08x\n",
50762306a36Sopenharmony_ci		prmd->pd.name, desc,
50862306a36Sopenharmony_ci		readl_relaxed(prmd->prm->base + prmd->pwrstctrl),
50962306a36Sopenharmony_ci		readl_relaxed(prmd->prm->base + prmd->pwrstst));
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci#else
51262306a36Sopenharmony_cistatic inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
51362306a36Sopenharmony_ci					      const char *desc)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci#endif
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic int omap_prm_domain_power_on(struct generic_pm_domain *domain)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct omap_prm_domain *prmd;
52162306a36Sopenharmony_ci	int ret;
52262306a36Sopenharmony_ci	u32 v, mode;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	prmd = genpd_to_prm_domain(domain);
52562306a36Sopenharmony_ci	if (!prmd->cap)
52662306a36Sopenharmony_ci		return 0;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	omap_prm_domain_show_state(prmd, "on: previous state");
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (prmd->pwrstctrl_saved)
53162306a36Sopenharmony_ci		v = prmd->pwrstctrl_saved;
53262306a36Sopenharmony_ci	else
53362306a36Sopenharmony_ci		v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (prmd->prm->data->flags & OMAP_PRM_RET_WHEN_IDLE)
53662306a36Sopenharmony_ci		mode = OMAP_PRMD_RETENTION;
53762306a36Sopenharmony_ci	else
53862306a36Sopenharmony_ci		mode = OMAP_PRMD_ON_ACTIVE;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	writel_relaxed((v & ~PRM_POWERSTATE_MASK) | mode,
54162306a36Sopenharmony_ci		       prmd->prm->base + prmd->pwrstctrl);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* wait for the transition bit to get cleared */
54462306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
54562306a36Sopenharmony_ci					 v, !(v & PRM_ST_INTRANSITION), 1,
54662306a36Sopenharmony_ci					 PRM_STATE_MAX_WAIT);
54762306a36Sopenharmony_ci	if (ret)
54862306a36Sopenharmony_ci		dev_err(prmd->dev, "%s: %s timed out\n",
54962306a36Sopenharmony_ci			prmd->pd.name, __func__);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	omap_prm_domain_show_state(prmd, "on: new state");
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	return ret;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci/* No need to check for holes in the mask for the lowest mode */
55762306a36Sopenharmony_cistatic int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	return __ffs(prmd->cap->usable_modes);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic int omap_prm_domain_power_off(struct generic_pm_domain *domain)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct omap_prm_domain *prmd;
56562306a36Sopenharmony_ci	int ret;
56662306a36Sopenharmony_ci	u32 v;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	prmd = genpd_to_prm_domain(domain);
56962306a36Sopenharmony_ci	if (!prmd->cap)
57062306a36Sopenharmony_ci		return 0;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	omap_prm_domain_show_state(prmd, "off: previous state");
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
57562306a36Sopenharmony_ci	prmd->pwrstctrl_saved = v;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	v &= ~PRM_POWERSTATE_MASK;
57862306a36Sopenharmony_ci	v |= omap_prm_domain_find_lowest(prmd);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (prmd->cap->statechange)
58162306a36Sopenharmony_ci		v |= PRM_LOWPOWERSTATECHANGE;
58262306a36Sopenharmony_ci	if (prmd->cap->logicretstate)
58362306a36Sopenharmony_ci		v &= ~PRM_LOGICRETSTATE;
58462306a36Sopenharmony_ci	else
58562306a36Sopenharmony_ci		v |= PRM_LOGICRETSTATE;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	/* wait for the transition bit to get cleared */
59062306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
59162306a36Sopenharmony_ci					 v, !(v & PRM_ST_INTRANSITION), 1,
59262306a36Sopenharmony_ci					 PRM_STATE_MAX_WAIT);
59362306a36Sopenharmony_ci	if (ret)
59462306a36Sopenharmony_ci		dev_warn(prmd->dev, "%s: %s timed out\n",
59562306a36Sopenharmony_ci			 __func__, prmd->pd.name);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	omap_prm_domain_show_state(prmd, "off: new state");
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return 0;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci/*
60362306a36Sopenharmony_ci * Note that ti-sysc already manages the module clocks separately so
60462306a36Sopenharmony_ci * no need to manage those. Interconnect instances need clocks managed
60562306a36Sopenharmony_ci * for simple-pm-bus.
60662306a36Sopenharmony_ci */
60762306a36Sopenharmony_cistatic int omap_prm_domain_attach_clock(struct device *dev,
60862306a36Sopenharmony_ci					struct omap_prm_domain *prmd)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
61162306a36Sopenharmony_ci	int error;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (!of_device_is_compatible(np, "simple-pm-bus"))
61462306a36Sopenharmony_ci		return 0;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (!of_property_read_bool(np, "clocks"))
61762306a36Sopenharmony_ci		return 0;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	error = pm_clk_create(dev);
62062306a36Sopenharmony_ci	if (error)
62162306a36Sopenharmony_ci		return error;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	error = of_pm_clk_add_clks(dev);
62462306a36Sopenharmony_ci	if (error < 0) {
62562306a36Sopenharmony_ci		pm_clk_destroy(dev);
62662306a36Sopenharmony_ci		return error;
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	prmd->uses_pm_clk = 1;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return 0;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic int omap_prm_domain_attach_dev(struct generic_pm_domain *domain,
63562306a36Sopenharmony_ci				      struct device *dev)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct generic_pm_domain_data *genpd_data;
63862306a36Sopenharmony_ci	struct of_phandle_args pd_args;
63962306a36Sopenharmony_ci	struct omap_prm_domain *prmd;
64062306a36Sopenharmony_ci	struct device_node *np;
64162306a36Sopenharmony_ci	int ret;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	prmd = genpd_to_prm_domain(domain);
64462306a36Sopenharmony_ci	np = dev->of_node;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	ret = of_parse_phandle_with_args(np, "power-domains",
64762306a36Sopenharmony_ci					 "#power-domain-cells", 0, &pd_args);
64862306a36Sopenharmony_ci	if (ret < 0)
64962306a36Sopenharmony_ci		return ret;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	if (pd_args.args_count != 0)
65262306a36Sopenharmony_ci		dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n",
65362306a36Sopenharmony_ci			 prmd->pd.name, pd_args.args_count);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	genpd_data = dev_gpd_data(dev);
65662306a36Sopenharmony_ci	genpd_data->data = NULL;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	ret = omap_prm_domain_attach_clock(dev, prmd);
65962306a36Sopenharmony_ci	if (ret)
66062306a36Sopenharmony_ci		return ret;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	return 0;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic void omap_prm_domain_detach_dev(struct generic_pm_domain *domain,
66662306a36Sopenharmony_ci				       struct device *dev)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	struct generic_pm_domain_data *genpd_data;
66962306a36Sopenharmony_ci	struct omap_prm_domain *prmd;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	prmd = genpd_to_prm_domain(domain);
67262306a36Sopenharmony_ci	if (prmd->uses_pm_clk)
67362306a36Sopenharmony_ci		pm_clk_destroy(dev);
67462306a36Sopenharmony_ci	genpd_data = dev_gpd_data(dev);
67562306a36Sopenharmony_ci	genpd_data->data = NULL;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic int omap_prm_domain_init(struct device *dev, struct omap_prm *prm)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct omap_prm_domain *prmd;
68162306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
68262306a36Sopenharmony_ci	const struct omap_prm_data *data;
68362306a36Sopenharmony_ci	const char *name;
68462306a36Sopenharmony_ci	int error;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	if (!of_property_present(dev->of_node, "#power-domain-cells"))
68762306a36Sopenharmony_ci		return 0;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	of_node_put(dev->of_node);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL);
69262306a36Sopenharmony_ci	if (!prmd)
69362306a36Sopenharmony_ci		return -ENOMEM;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	data = prm->data;
69662306a36Sopenharmony_ci	name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s",
69762306a36Sopenharmony_ci			      data->name);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	prmd->dev = dev;
70062306a36Sopenharmony_ci	prmd->prm = prm;
70162306a36Sopenharmony_ci	prmd->cap = prmd->prm->data->dmap;
70262306a36Sopenharmony_ci	prmd->pwrstctrl = prmd->prm->data->pwrstctrl;
70362306a36Sopenharmony_ci	prmd->pwrstst = prmd->prm->data->pwrstst;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	prmd->pd.name = name;
70662306a36Sopenharmony_ci	prmd->pd.power_on = omap_prm_domain_power_on;
70762306a36Sopenharmony_ci	prmd->pd.power_off = omap_prm_domain_power_off;
70862306a36Sopenharmony_ci	prmd->pd.attach_dev = omap_prm_domain_attach_dev;
70962306a36Sopenharmony_ci	prmd->pd.detach_dev = omap_prm_domain_detach_dev;
71062306a36Sopenharmony_ci	prmd->pd.flags = GENPD_FLAG_PM_CLK;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	pm_genpd_init(&prmd->pd, NULL, true);
71362306a36Sopenharmony_ci	error = of_genpd_add_provider_simple(np, &prmd->pd);
71462306a36Sopenharmony_ci	if (error)
71562306a36Sopenharmony_ci		pm_genpd_remove(&prmd->pd);
71662306a36Sopenharmony_ci	else
71762306a36Sopenharmony_ci		prm->prmd = prmd;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	return error;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	if (reset->mask & BIT(id))
72562306a36Sopenharmony_ci		return true;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	return false;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic int omap_reset_get_st_bit(struct omap_reset_data *reset,
73162306a36Sopenharmony_ci				 unsigned long id)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	const struct omap_rst_map *map = reset->prm->data->rstmap;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	while (map->rst >= 0) {
73662306a36Sopenharmony_ci		if (map->rst == id)
73762306a36Sopenharmony_ci			return map->st;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		map++;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return id;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic int omap_reset_status(struct reset_controller_dev *rcdev,
74662306a36Sopenharmony_ci			     unsigned long id)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct omap_reset_data *reset = to_omap_reset_data(rcdev);
74962306a36Sopenharmony_ci	u32 v;
75062306a36Sopenharmony_ci	int st_bit = omap_reset_get_st_bit(reset, id);
75162306a36Sopenharmony_ci	bool has_rstst = reset->prm->data->rstst ||
75262306a36Sopenharmony_ci		(reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	/* Check if we have rstst */
75562306a36Sopenharmony_ci	if (!has_rstst)
75662306a36Sopenharmony_ci		return -ENOTSUPP;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* Check if hw reset line is asserted */
75962306a36Sopenharmony_ci	v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
76062306a36Sopenharmony_ci	if (v & BIT(id))
76162306a36Sopenharmony_ci		return 1;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	/*
76462306a36Sopenharmony_ci	 * Check reset status, high value means reset sequence has been
76562306a36Sopenharmony_ci	 * completed successfully so we can return 0 here (reset deasserted)
76662306a36Sopenharmony_ci	 */
76762306a36Sopenharmony_ci	v = readl_relaxed(reset->prm->base + reset->prm->data->rstst);
76862306a36Sopenharmony_ci	v >>= st_bit;
76962306a36Sopenharmony_ci	v &= 1;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	return !v;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int omap_reset_assert(struct reset_controller_dev *rcdev,
77562306a36Sopenharmony_ci			     unsigned long id)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	struct omap_reset_data *reset = to_omap_reset_data(rcdev);
77862306a36Sopenharmony_ci	u32 v;
77962306a36Sopenharmony_ci	unsigned long flags;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/* assert the reset control line */
78262306a36Sopenharmony_ci	spin_lock_irqsave(&reset->lock, flags);
78362306a36Sopenharmony_ci	v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
78462306a36Sopenharmony_ci	v |= 1 << id;
78562306a36Sopenharmony_ci	writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
78662306a36Sopenharmony_ci	spin_unlock_irqrestore(&reset->lock, flags);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	return 0;
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic int omap_reset_deassert(struct reset_controller_dev *rcdev,
79262306a36Sopenharmony_ci			       unsigned long id)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	struct omap_reset_data *reset = to_omap_reset_data(rcdev);
79562306a36Sopenharmony_ci	u32 v;
79662306a36Sopenharmony_ci	int st_bit;
79762306a36Sopenharmony_ci	bool has_rstst;
79862306a36Sopenharmony_ci	unsigned long flags;
79962306a36Sopenharmony_ci	struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev);
80062306a36Sopenharmony_ci	int ret = 0;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	/* Nothing to do if the reset is already deasserted */
80362306a36Sopenharmony_ci	if (!omap_reset_status(rcdev, id))
80462306a36Sopenharmony_ci		return 0;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	has_rstst = reset->prm->data->rstst ||
80762306a36Sopenharmony_ci		(reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (has_rstst) {
81062306a36Sopenharmony_ci		st_bit = omap_reset_get_st_bit(reset, id);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		/* Clear the reset status by writing 1 to the status bit */
81362306a36Sopenharmony_ci		v = 1 << st_bit;
81462306a36Sopenharmony_ci		writel_relaxed(v, reset->prm->base + reset->prm->data->rstst);
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (reset->clkdm)
81862306a36Sopenharmony_ci		pdata->clkdm_deny_idle(reset->clkdm);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* de-assert the reset control line */
82162306a36Sopenharmony_ci	spin_lock_irqsave(&reset->lock, flags);
82262306a36Sopenharmony_ci	v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
82362306a36Sopenharmony_ci	v &= ~(1 << id);
82462306a36Sopenharmony_ci	writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
82562306a36Sopenharmony_ci	spin_unlock_irqrestore(&reset->lock, flags);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* wait for the reset bit to clear */
82862306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
82962306a36Sopenharmony_ci						reset->prm->data->rstctrl,
83062306a36Sopenharmony_ci						v, !(v & BIT(id)), 1,
83162306a36Sopenharmony_ci						OMAP_RESET_MAX_WAIT);
83262306a36Sopenharmony_ci	if (ret)
83362306a36Sopenharmony_ci		pr_err("%s: timedout waiting for %s:%lu\n", __func__,
83462306a36Sopenharmony_ci		       reset->prm->data->name, id);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* wait for the status to be set */
83762306a36Sopenharmony_ci	if (has_rstst) {
83862306a36Sopenharmony_ci		ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
83962306a36Sopenharmony_ci						 reset->prm->data->rstst,
84062306a36Sopenharmony_ci						 v, v & BIT(st_bit), 1,
84162306a36Sopenharmony_ci						 OMAP_RESET_MAX_WAIT);
84262306a36Sopenharmony_ci		if (ret)
84362306a36Sopenharmony_ci			pr_err("%s: timedout waiting for %s:%lu\n", __func__,
84462306a36Sopenharmony_ci			       reset->prm->data->name, id);
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	if (reset->clkdm)
84862306a36Sopenharmony_ci		pdata->clkdm_allow_idle(reset->clkdm);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	return ret;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic const struct reset_control_ops omap_reset_ops = {
85462306a36Sopenharmony_ci	.assert		= omap_reset_assert,
85562306a36Sopenharmony_ci	.deassert	= omap_reset_deassert,
85662306a36Sopenharmony_ci	.status		= omap_reset_status,
85762306a36Sopenharmony_ci};
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_cistatic int omap_prm_reset_xlate(struct reset_controller_dev *rcdev,
86062306a36Sopenharmony_ci				const struct of_phandle_args *reset_spec)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	struct omap_reset_data *reset = to_omap_reset_data(rcdev);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (!_is_valid_reset(reset, reset_spec->args[0]))
86562306a36Sopenharmony_ci		return -EINVAL;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	return reset_spec->args[0];
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic int omap_prm_reset_init(struct platform_device *pdev,
87162306a36Sopenharmony_ci			       struct omap_prm *prm)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct omap_reset_data *reset;
87462306a36Sopenharmony_ci	const struct omap_rst_map *map;
87562306a36Sopenharmony_ci	struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev);
87662306a36Sopenharmony_ci	char buf[32];
87762306a36Sopenharmony_ci	u32 v;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/*
88062306a36Sopenharmony_ci	 * Check if we have controllable resets. If either rstctrl is non-zero
88162306a36Sopenharmony_ci	 * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
88262306a36Sopenharmony_ci	 * for the domain.
88362306a36Sopenharmony_ci	 */
88462306a36Sopenharmony_ci	if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL))
88562306a36Sopenharmony_ci		return 0;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* Check if we have the pdata callbacks in place */
88862306a36Sopenharmony_ci	if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle ||
88962306a36Sopenharmony_ci	    !pdata->clkdm_allow_idle)
89062306a36Sopenharmony_ci		return -EINVAL;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	map = prm->data->rstmap;
89362306a36Sopenharmony_ci	if (!map)
89462306a36Sopenharmony_ci		return -EINVAL;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
89762306a36Sopenharmony_ci	if (!reset)
89862306a36Sopenharmony_ci		return -ENOMEM;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	reset->rcdev.owner = THIS_MODULE;
90162306a36Sopenharmony_ci	reset->rcdev.ops = &omap_reset_ops;
90262306a36Sopenharmony_ci	reset->rcdev.of_node = pdev->dev.of_node;
90362306a36Sopenharmony_ci	reset->rcdev.nr_resets = OMAP_MAX_RESETS;
90462306a36Sopenharmony_ci	reset->rcdev.of_xlate = omap_prm_reset_xlate;
90562306a36Sopenharmony_ci	reset->rcdev.of_reset_n_cells = 1;
90662306a36Sopenharmony_ci	reset->dev = &pdev->dev;
90762306a36Sopenharmony_ci	spin_lock_init(&reset->lock);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	reset->prm = prm;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name :
91262306a36Sopenharmony_ci		prm->data->name);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) {
91562306a36Sopenharmony_ci		reset->clkdm = pdata->clkdm_lookup(buf);
91662306a36Sopenharmony_ci		if (!reset->clkdm)
91762306a36Sopenharmony_ci			return -EINVAL;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	while (map->rst >= 0) {
92162306a36Sopenharmony_ci		reset->mask |= BIT(map->rst);
92262306a36Sopenharmony_ci		map++;
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/* Quirk handling to assert rst_map_012 bits on reset and avoid errors */
92662306a36Sopenharmony_ci	if (prm->data->rstmap == rst_map_012) {
92762306a36Sopenharmony_ci		v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
92862306a36Sopenharmony_ci		if ((v & reset->mask) != reset->mask) {
92962306a36Sopenharmony_ci			dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v);
93062306a36Sopenharmony_ci			writel_relaxed(reset->mask, reset->prm->base +
93162306a36Sopenharmony_ci				       reset->prm->data->rstctrl);
93262306a36Sopenharmony_ci		}
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic int omap_prm_probe(struct platform_device *pdev)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct resource *res;
94162306a36Sopenharmony_ci	const struct omap_prm_data *data;
94262306a36Sopenharmony_ci	struct omap_prm *prm;
94362306a36Sopenharmony_ci	int ret;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	data = of_device_get_match_data(&pdev->dev);
94662306a36Sopenharmony_ci	if (!data)
94762306a36Sopenharmony_ci		return -ENOTSUPP;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL);
95062306a36Sopenharmony_ci	if (!prm)
95162306a36Sopenharmony_ci		return -ENOMEM;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	prm->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
95462306a36Sopenharmony_ci	if (IS_ERR(prm->base))
95562306a36Sopenharmony_ci		return PTR_ERR(prm->base);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	while (data->base != res->start) {
95862306a36Sopenharmony_ci		if (!data->base)
95962306a36Sopenharmony_ci			return -EINVAL;
96062306a36Sopenharmony_ci		data++;
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	prm->data = data;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	ret = omap_prm_domain_init(&pdev->dev, prm);
96662306a36Sopenharmony_ci	if (ret)
96762306a36Sopenharmony_ci		return ret;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	ret = omap_prm_reset_init(pdev, prm);
97062306a36Sopenharmony_ci	if (ret)
97162306a36Sopenharmony_ci		goto err_domain;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	return 0;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cierr_domain:
97662306a36Sopenharmony_ci	of_genpd_del_provider(pdev->dev.of_node);
97762306a36Sopenharmony_ci	pm_genpd_remove(&prm->prmd->pd);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	return ret;
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic struct platform_driver omap_prm_driver = {
98362306a36Sopenharmony_ci	.probe = omap_prm_probe,
98462306a36Sopenharmony_ci	.driver = {
98562306a36Sopenharmony_ci		.name		= KBUILD_MODNAME,
98662306a36Sopenharmony_ci		.of_match_table	= omap_prm_id_table,
98762306a36Sopenharmony_ci	},
98862306a36Sopenharmony_ci};
98962306a36Sopenharmony_cibuiltin_platform_driver(omap_prm_driver);
990