xref: /openbmc/linux/drivers/pmdomain/ti/omap_prm.c (revision e2ad626f8f409899baf1bf192d0533a851128b19)
1*e2ad626fSUlf Hansson // SPDX-License-Identifier: GPL-2.0
2*e2ad626fSUlf Hansson /*
3*e2ad626fSUlf Hansson  * OMAP2+ PRM driver
4*e2ad626fSUlf Hansson  *
5*e2ad626fSUlf Hansson  * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
6*e2ad626fSUlf Hansson  *	Tero Kristo <t-kristo@ti.com>
7*e2ad626fSUlf Hansson  */
8*e2ad626fSUlf Hansson 
9*e2ad626fSUlf Hansson #include <linux/kernel.h>
10*e2ad626fSUlf Hansson #include <linux/clk.h>
11*e2ad626fSUlf Hansson #include <linux/device.h>
12*e2ad626fSUlf Hansson #include <linux/io.h>
13*e2ad626fSUlf Hansson #include <linux/iopoll.h>
14*e2ad626fSUlf Hansson #include <linux/module.h>
15*e2ad626fSUlf Hansson #include <linux/of.h>
16*e2ad626fSUlf Hansson #include <linux/platform_device.h>
17*e2ad626fSUlf Hansson #include <linux/pm_clock.h>
18*e2ad626fSUlf Hansson #include <linux/pm_domain.h>
19*e2ad626fSUlf Hansson #include <linux/reset-controller.h>
20*e2ad626fSUlf Hansson #include <linux/delay.h>
21*e2ad626fSUlf Hansson 
22*e2ad626fSUlf Hansson #include <linux/platform_data/ti-prm.h>
23*e2ad626fSUlf Hansson 
24*e2ad626fSUlf Hansson enum omap_prm_domain_mode {
25*e2ad626fSUlf Hansson 	OMAP_PRMD_OFF,
26*e2ad626fSUlf Hansson 	OMAP_PRMD_RETENTION,
27*e2ad626fSUlf Hansson 	OMAP_PRMD_ON_INACTIVE,
28*e2ad626fSUlf Hansson 	OMAP_PRMD_ON_ACTIVE,
29*e2ad626fSUlf Hansson };
30*e2ad626fSUlf Hansson 
31*e2ad626fSUlf Hansson struct omap_prm_domain_map {
32*e2ad626fSUlf Hansson 	unsigned int usable_modes;	/* Mask of hardware supported modes */
33*e2ad626fSUlf Hansson 	unsigned long statechange:1;	/* Optional low-power state change */
34*e2ad626fSUlf Hansson 	unsigned long logicretstate:1;	/* Optional logic off mode */
35*e2ad626fSUlf Hansson };
36*e2ad626fSUlf Hansson 
37*e2ad626fSUlf Hansson struct omap_prm_domain {
38*e2ad626fSUlf Hansson 	struct device *dev;
39*e2ad626fSUlf Hansson 	struct omap_prm *prm;
40*e2ad626fSUlf Hansson 	struct generic_pm_domain pd;
41*e2ad626fSUlf Hansson 	u16 pwrstctrl;
42*e2ad626fSUlf Hansson 	u16 pwrstst;
43*e2ad626fSUlf Hansson 	const struct omap_prm_domain_map *cap;
44*e2ad626fSUlf Hansson 	u32 pwrstctrl_saved;
45*e2ad626fSUlf Hansson 	unsigned int uses_pm_clk:1;
46*e2ad626fSUlf Hansson };
47*e2ad626fSUlf Hansson 
48*e2ad626fSUlf Hansson struct omap_rst_map {
49*e2ad626fSUlf Hansson 	s8 rst;
50*e2ad626fSUlf Hansson 	s8 st;
51*e2ad626fSUlf Hansson };
52*e2ad626fSUlf Hansson 
53*e2ad626fSUlf Hansson struct omap_prm_data {
54*e2ad626fSUlf Hansson 	u32 base;
55*e2ad626fSUlf Hansson 	const char *name;
56*e2ad626fSUlf Hansson 	const char *clkdm_name;
57*e2ad626fSUlf Hansson 	u16 pwrstctrl;
58*e2ad626fSUlf Hansson 	u16 pwrstst;
59*e2ad626fSUlf Hansson 	const struct omap_prm_domain_map *dmap;
60*e2ad626fSUlf Hansson 	u16 rstctrl;
61*e2ad626fSUlf Hansson 	u16 rstst;
62*e2ad626fSUlf Hansson 	const struct omap_rst_map *rstmap;
63*e2ad626fSUlf Hansson 	u8 flags;
64*e2ad626fSUlf Hansson };
65*e2ad626fSUlf Hansson 
66*e2ad626fSUlf Hansson struct omap_prm {
67*e2ad626fSUlf Hansson 	const struct omap_prm_data *data;
68*e2ad626fSUlf Hansson 	void __iomem *base;
69*e2ad626fSUlf Hansson 	struct omap_prm_domain *prmd;
70*e2ad626fSUlf Hansson };
71*e2ad626fSUlf Hansson 
72*e2ad626fSUlf Hansson struct omap_reset_data {
73*e2ad626fSUlf Hansson 	struct reset_controller_dev rcdev;
74*e2ad626fSUlf Hansson 	struct omap_prm *prm;
75*e2ad626fSUlf Hansson 	u32 mask;
76*e2ad626fSUlf Hansson 	spinlock_t lock;
77*e2ad626fSUlf Hansson 	struct clockdomain *clkdm;
78*e2ad626fSUlf Hansson 	struct device *dev;
79*e2ad626fSUlf Hansson };
80*e2ad626fSUlf Hansson 
81*e2ad626fSUlf Hansson #define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd)
82*e2ad626fSUlf Hansson #define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev)
83*e2ad626fSUlf Hansson 
84*e2ad626fSUlf Hansson #define OMAP_MAX_RESETS		8
85*e2ad626fSUlf Hansson #define OMAP_RESET_MAX_WAIT	10000
86*e2ad626fSUlf Hansson 
87*e2ad626fSUlf Hansson #define OMAP_PRM_HAS_RSTCTRL	BIT(0)
88*e2ad626fSUlf Hansson #define OMAP_PRM_HAS_RSTST	BIT(1)
89*e2ad626fSUlf Hansson #define OMAP_PRM_HAS_NO_CLKDM	BIT(2)
90*e2ad626fSUlf Hansson #define OMAP_PRM_RET_WHEN_IDLE	BIT(3)
91*e2ad626fSUlf Hansson 
92*e2ad626fSUlf Hansson #define OMAP_PRM_HAS_RESETS	(OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
93*e2ad626fSUlf Hansson 
94*e2ad626fSUlf Hansson #define PRM_STATE_MAX_WAIT	10000
95*e2ad626fSUlf Hansson #define PRM_LOGICRETSTATE	BIT(2)
96*e2ad626fSUlf Hansson #define PRM_LOWPOWERSTATECHANGE	BIT(4)
97*e2ad626fSUlf Hansson #define PRM_POWERSTATE_MASK	OMAP_PRMD_ON_ACTIVE
98*e2ad626fSUlf Hansson 
99*e2ad626fSUlf Hansson #define PRM_ST_INTRANSITION	BIT(20)
100*e2ad626fSUlf Hansson 
101*e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_all = {
102*e2ad626fSUlf Hansson 	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
103*e2ad626fSUlf Hansson 			BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF),
104*e2ad626fSUlf Hansson 	.statechange = 1,
105*e2ad626fSUlf Hansson 	.logicretstate = 1,
106*e2ad626fSUlf Hansson };
107*e2ad626fSUlf Hansson 
108*e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_noinact = {
109*e2ad626fSUlf Hansson 	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) |
110*e2ad626fSUlf Hansson 			BIT(OMAP_PRMD_OFF),
111*e2ad626fSUlf Hansson 	.statechange = 1,
112*e2ad626fSUlf Hansson 	.logicretstate = 1,
113*e2ad626fSUlf Hansson };
114*e2ad626fSUlf Hansson 
115*e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_nooff = {
116*e2ad626fSUlf Hansson 	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
117*e2ad626fSUlf Hansson 			BIT(OMAP_PRMD_RETENTION),
118*e2ad626fSUlf Hansson 	.statechange = 1,
119*e2ad626fSUlf Hansson 	.logicretstate = 1,
120*e2ad626fSUlf Hansson };
121*e2ad626fSUlf Hansson 
122*e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_onoff_noauto = {
123*e2ad626fSUlf Hansson 	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF),
124*e2ad626fSUlf Hansson 	.statechange = 1,
125*e2ad626fSUlf Hansson };
126*e2ad626fSUlf Hansson 
127*e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_alwon = {
128*e2ad626fSUlf Hansson 	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE),
129*e2ad626fSUlf Hansson };
130*e2ad626fSUlf Hansson 
131*e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_reton = {
132*e2ad626fSUlf Hansson 	.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION),
133*e2ad626fSUlf Hansson 	.statechange = 1,
134*e2ad626fSUlf Hansson 	.logicretstate = 1,
135*e2ad626fSUlf Hansson };
136*e2ad626fSUlf Hansson 
137*e2ad626fSUlf Hansson static const struct omap_rst_map rst_map_0[] = {
138*e2ad626fSUlf Hansson 	{ .rst = 0, .st = 0 },
139*e2ad626fSUlf Hansson 	{ .rst = -1 },
140*e2ad626fSUlf Hansson };
141*e2ad626fSUlf Hansson 
142*e2ad626fSUlf Hansson static const struct omap_rst_map rst_map_01[] = {
143*e2ad626fSUlf Hansson 	{ .rst = 0, .st = 0 },
144*e2ad626fSUlf Hansson 	{ .rst = 1, .st = 1 },
145*e2ad626fSUlf Hansson 	{ .rst = -1 },
146*e2ad626fSUlf Hansson };
147*e2ad626fSUlf Hansson 
148*e2ad626fSUlf Hansson static const struct omap_rst_map rst_map_012[] = {
149*e2ad626fSUlf Hansson 	{ .rst = 0, .st = 0 },
150*e2ad626fSUlf Hansson 	{ .rst = 1, .st = 1 },
151*e2ad626fSUlf Hansson 	{ .rst = 2, .st = 2 },
152*e2ad626fSUlf Hansson 	{ .rst = -1 },
153*e2ad626fSUlf Hansson };
154*e2ad626fSUlf Hansson 
155*e2ad626fSUlf Hansson static const struct omap_prm_data omap4_prm_data[] = {
156*e2ad626fSUlf Hansson 	{
157*e2ad626fSUlf Hansson 		.name = "mpu", .base = 0x4a306300,
158*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
159*e2ad626fSUlf Hansson 	},
160*e2ad626fSUlf Hansson 	{
161*e2ad626fSUlf Hansson 		.name = "tesla", .base = 0x4a306400,
162*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
163*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
164*e2ad626fSUlf Hansson 	},
165*e2ad626fSUlf Hansson 	{
166*e2ad626fSUlf Hansson 		.name = "abe", .base = 0x4a306500,
167*e2ad626fSUlf Hansson 		.pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all,
168*e2ad626fSUlf Hansson 	},
169*e2ad626fSUlf Hansson 	{
170*e2ad626fSUlf Hansson 		.name = "always_on_core", .base = 0x4a306600,
171*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
172*e2ad626fSUlf Hansson 	},
173*e2ad626fSUlf Hansson 	{
174*e2ad626fSUlf Hansson 		.name = "core", .base = 0x4a306700,
175*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
176*e2ad626fSUlf Hansson 		.rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati",
177*e2ad626fSUlf Hansson 		.rstmap = rst_map_012,
178*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_RET_WHEN_IDLE,
179*e2ad626fSUlf Hansson 	},
180*e2ad626fSUlf Hansson 	{
181*e2ad626fSUlf Hansson 		.name = "ivahd", .base = 0x4a306f00,
182*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
183*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
184*e2ad626fSUlf Hansson 	},
185*e2ad626fSUlf Hansson 	{
186*e2ad626fSUlf Hansson 		.name = "cam", .base = 0x4a307000,
187*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
188*e2ad626fSUlf Hansson 	},
189*e2ad626fSUlf Hansson 	{
190*e2ad626fSUlf Hansson 		.name = "dss", .base = 0x4a307100,
191*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact
192*e2ad626fSUlf Hansson 	},
193*e2ad626fSUlf Hansson 	{
194*e2ad626fSUlf Hansson 		.name = "gfx", .base = 0x4a307200,
195*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
196*e2ad626fSUlf Hansson 	},
197*e2ad626fSUlf Hansson 	{
198*e2ad626fSUlf Hansson 		.name = "l3init", .base = 0x4a307300,
199*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton
200*e2ad626fSUlf Hansson 	},
201*e2ad626fSUlf Hansson 	{
202*e2ad626fSUlf Hansson 		.name = "l4per", .base = 0x4a307400,
203*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
204*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_RET_WHEN_IDLE,
205*e2ad626fSUlf Hansson 	},
206*e2ad626fSUlf Hansson 	{
207*e2ad626fSUlf Hansson 		.name = "cefuse", .base = 0x4a307600,
208*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
209*e2ad626fSUlf Hansson 	},
210*e2ad626fSUlf Hansson 	{
211*e2ad626fSUlf Hansson 		.name = "wkup", .base = 0x4a307700,
212*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
213*e2ad626fSUlf Hansson 	},
214*e2ad626fSUlf Hansson 	{
215*e2ad626fSUlf Hansson 		.name = "emu", .base = 0x4a307900,
216*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
217*e2ad626fSUlf Hansson 	},
218*e2ad626fSUlf Hansson 	{
219*e2ad626fSUlf Hansson 		.name = "device", .base = 0x4a307b00,
220*e2ad626fSUlf Hansson 		.rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01,
221*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
222*e2ad626fSUlf Hansson 	},
223*e2ad626fSUlf Hansson 	{ },
224*e2ad626fSUlf Hansson };
225*e2ad626fSUlf Hansson 
226*e2ad626fSUlf Hansson static const struct omap_prm_data omap5_prm_data[] = {
227*e2ad626fSUlf Hansson 	{
228*e2ad626fSUlf Hansson 		.name = "mpu", .base = 0x4ae06300,
229*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
230*e2ad626fSUlf Hansson 	},
231*e2ad626fSUlf Hansson 	{
232*e2ad626fSUlf Hansson 		.name = "dsp", .base = 0x4ae06400,
233*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
234*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
235*e2ad626fSUlf Hansson 	},
236*e2ad626fSUlf Hansson 	{
237*e2ad626fSUlf Hansson 		.name = "abe", .base = 0x4ae06500,
238*e2ad626fSUlf Hansson 		.pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff,
239*e2ad626fSUlf Hansson 	},
240*e2ad626fSUlf Hansson 	{
241*e2ad626fSUlf Hansson 		.name = "coreaon", .base = 0x4ae06600,
242*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
243*e2ad626fSUlf Hansson 	},
244*e2ad626fSUlf Hansson 	{
245*e2ad626fSUlf Hansson 		.name = "core", .base = 0x4ae06700,
246*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
247*e2ad626fSUlf Hansson 		.rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu",
248*e2ad626fSUlf Hansson 		.rstmap = rst_map_012
249*e2ad626fSUlf Hansson 	},
250*e2ad626fSUlf Hansson 	{
251*e2ad626fSUlf Hansson 		.name = "iva", .base = 0x4ae07200,
252*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
253*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
254*e2ad626fSUlf Hansson 	},
255*e2ad626fSUlf Hansson 	{
256*e2ad626fSUlf Hansson 		.name = "cam", .base = 0x4ae07300,
257*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
258*e2ad626fSUlf Hansson 	},
259*e2ad626fSUlf Hansson 	{
260*e2ad626fSUlf Hansson 		.name = "dss", .base = 0x4ae07400,
261*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact
262*e2ad626fSUlf Hansson 	},
263*e2ad626fSUlf Hansson 	{
264*e2ad626fSUlf Hansson 		.name = "gpu", .base = 0x4ae07500,
265*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
266*e2ad626fSUlf Hansson 	},
267*e2ad626fSUlf Hansson 	{
268*e2ad626fSUlf Hansson 		.name = "l3init", .base = 0x4ae07600,
269*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton
270*e2ad626fSUlf Hansson 	},
271*e2ad626fSUlf Hansson 	{
272*e2ad626fSUlf Hansson 		.name = "custefuse", .base = 0x4ae07700,
273*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
274*e2ad626fSUlf Hansson 	},
275*e2ad626fSUlf Hansson 	{
276*e2ad626fSUlf Hansson 		.name = "wkupaon", .base = 0x4ae07800,
277*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
278*e2ad626fSUlf Hansson 	},
279*e2ad626fSUlf Hansson 	{
280*e2ad626fSUlf Hansson 		.name = "emu", .base = 0x4ae07a00,
281*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
282*e2ad626fSUlf Hansson 	},
283*e2ad626fSUlf Hansson 	{
284*e2ad626fSUlf Hansson 		.name = "device", .base = 0x4ae07c00,
285*e2ad626fSUlf Hansson 		.rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01,
286*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
287*e2ad626fSUlf Hansson 	},
288*e2ad626fSUlf Hansson 	{ },
289*e2ad626fSUlf Hansson };
290*e2ad626fSUlf Hansson 
291*e2ad626fSUlf Hansson static const struct omap_prm_data dra7_prm_data[] = {
292*e2ad626fSUlf Hansson 	{
293*e2ad626fSUlf Hansson 		.name = "mpu", .base = 0x4ae06300,
294*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
295*e2ad626fSUlf Hansson 	},
296*e2ad626fSUlf Hansson 	{
297*e2ad626fSUlf Hansson 		.name = "dsp1", .base = 0x4ae06400,
298*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
299*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01,
300*e2ad626fSUlf Hansson 	},
301*e2ad626fSUlf Hansson 	{
302*e2ad626fSUlf Hansson 		.name = "ipu", .base = 0x4ae06500,
303*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
304*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012,
305*e2ad626fSUlf Hansson 		.clkdm_name = "ipu1"
306*e2ad626fSUlf Hansson 	},
307*e2ad626fSUlf Hansson 	{
308*e2ad626fSUlf Hansson 		.name = "coreaon", .base = 0x4ae06628,
309*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
310*e2ad626fSUlf Hansson 	},
311*e2ad626fSUlf Hansson 	{
312*e2ad626fSUlf Hansson 		.name = "core", .base = 0x4ae06700,
313*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
314*e2ad626fSUlf Hansson 		.rstctrl = 0x210, .rstst = 0x214, .rstmap = rst_map_012,
315*e2ad626fSUlf Hansson 		.clkdm_name = "ipu2"
316*e2ad626fSUlf Hansson 	},
317*e2ad626fSUlf Hansson 	{
318*e2ad626fSUlf Hansson 		.name = "iva", .base = 0x4ae06f00,
319*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
320*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012,
321*e2ad626fSUlf Hansson 	},
322*e2ad626fSUlf Hansson 	{
323*e2ad626fSUlf Hansson 		.name = "cam", .base = 0x4ae07000,
324*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
325*e2ad626fSUlf Hansson 	},
326*e2ad626fSUlf Hansson 	{
327*e2ad626fSUlf Hansson 		.name = "dss", .base = 0x4ae07100,
328*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
329*e2ad626fSUlf Hansson 	},
330*e2ad626fSUlf Hansson 	{
331*e2ad626fSUlf Hansson 		.name = "gpu", .base = 0x4ae07200,
332*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
333*e2ad626fSUlf Hansson 	},
334*e2ad626fSUlf Hansson 	{
335*e2ad626fSUlf Hansson 		.name = "l3init", .base = 0x4ae07300,
336*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
337*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01,
338*e2ad626fSUlf Hansson 		.clkdm_name = "pcie"
339*e2ad626fSUlf Hansson 	},
340*e2ad626fSUlf Hansson 	{
341*e2ad626fSUlf Hansson 		.name = "l4per", .base = 0x4ae07400,
342*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
343*e2ad626fSUlf Hansson 	},
344*e2ad626fSUlf Hansson 	{
345*e2ad626fSUlf Hansson 		.name = "custefuse", .base = 0x4ae07600,
346*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
347*e2ad626fSUlf Hansson 	},
348*e2ad626fSUlf Hansson 	{
349*e2ad626fSUlf Hansson 		.name = "wkupaon", .base = 0x4ae07724,
350*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
351*e2ad626fSUlf Hansson 	},
352*e2ad626fSUlf Hansson 	{
353*e2ad626fSUlf Hansson 		.name = "emu", .base = 0x4ae07900,
354*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
355*e2ad626fSUlf Hansson 	},
356*e2ad626fSUlf Hansson 	{
357*e2ad626fSUlf Hansson 		.name = "dsp2", .base = 0x4ae07b00,
358*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
359*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
360*e2ad626fSUlf Hansson 	},
361*e2ad626fSUlf Hansson 	{
362*e2ad626fSUlf Hansson 		.name = "eve1", .base = 0x4ae07b40,
363*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
364*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
365*e2ad626fSUlf Hansson 	},
366*e2ad626fSUlf Hansson 	{
367*e2ad626fSUlf Hansson 		.name = "eve2", .base = 0x4ae07b80,
368*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
369*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
370*e2ad626fSUlf Hansson 	},
371*e2ad626fSUlf Hansson 	{
372*e2ad626fSUlf Hansson 		.name = "eve3", .base = 0x4ae07bc0,
373*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
374*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
375*e2ad626fSUlf Hansson 	},
376*e2ad626fSUlf Hansson 	{
377*e2ad626fSUlf Hansson 		.name = "eve4", .base = 0x4ae07c00,
378*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
379*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
380*e2ad626fSUlf Hansson 	},
381*e2ad626fSUlf Hansson 	{
382*e2ad626fSUlf Hansson 		.name = "rtc", .base = 0x4ae07c60,
383*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
384*e2ad626fSUlf Hansson 	},
385*e2ad626fSUlf Hansson 	{
386*e2ad626fSUlf Hansson 		.name = "vpe", .base = 0x4ae07c80,
387*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
388*e2ad626fSUlf Hansson 	},
389*e2ad626fSUlf Hansson 	{ },
390*e2ad626fSUlf Hansson };
391*e2ad626fSUlf Hansson 
392*e2ad626fSUlf Hansson static const struct omap_rst_map am3_per_rst_map[] = {
393*e2ad626fSUlf Hansson 	{ .rst = 1 },
394*e2ad626fSUlf Hansson 	{ .rst = -1 },
395*e2ad626fSUlf Hansson };
396*e2ad626fSUlf Hansson 
397*e2ad626fSUlf Hansson static const struct omap_rst_map am3_wkup_rst_map[] = {
398*e2ad626fSUlf Hansson 	{ .rst = 3, .st = 5 },
399*e2ad626fSUlf Hansson 	{ .rst = -1 },
400*e2ad626fSUlf Hansson };
401*e2ad626fSUlf Hansson 
402*e2ad626fSUlf Hansson static const struct omap_prm_data am3_prm_data[] = {
403*e2ad626fSUlf Hansson 	{
404*e2ad626fSUlf Hansson 		.name = "per", .base = 0x44e00c00,
405*e2ad626fSUlf Hansson 		.pwrstctrl = 0xc, .pwrstst = 0x8, .dmap = &omap_prm_noinact,
406*e2ad626fSUlf Hansson 		.rstctrl = 0x0, .rstmap = am3_per_rst_map,
407*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp"
408*e2ad626fSUlf Hansson 	},
409*e2ad626fSUlf Hansson 	{
410*e2ad626fSUlf Hansson 		.name = "wkup", .base = 0x44e00d00,
411*e2ad626fSUlf Hansson 		.pwrstctrl = 0x4, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
412*e2ad626fSUlf Hansson 		.rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map,
413*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
414*e2ad626fSUlf Hansson 	},
415*e2ad626fSUlf Hansson 	{
416*e2ad626fSUlf Hansson 		.name = "mpu", .base = 0x44e00e00,
417*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
418*e2ad626fSUlf Hansson 	},
419*e2ad626fSUlf Hansson 	{
420*e2ad626fSUlf Hansson 		.name = "device", .base = 0x44e00f00,
421*e2ad626fSUlf Hansson 		.rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01,
422*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
423*e2ad626fSUlf Hansson 	},
424*e2ad626fSUlf Hansson 	{
425*e2ad626fSUlf Hansson 		.name = "rtc", .base = 0x44e01000,
426*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
427*e2ad626fSUlf Hansson 	},
428*e2ad626fSUlf Hansson 	{
429*e2ad626fSUlf Hansson 		.name = "gfx", .base = 0x44e01100,
430*e2ad626fSUlf Hansson 		.pwrstctrl = 0, .pwrstst = 0x10, .dmap = &omap_prm_noinact,
431*e2ad626fSUlf Hansson 		.rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
432*e2ad626fSUlf Hansson 	},
433*e2ad626fSUlf Hansson 	{
434*e2ad626fSUlf Hansson 		.name = "cefuse", .base = 0x44e01200,
435*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
436*e2ad626fSUlf Hansson 	},
437*e2ad626fSUlf Hansson 	{ },
438*e2ad626fSUlf Hansson };
439*e2ad626fSUlf Hansson 
440*e2ad626fSUlf Hansson static const struct omap_rst_map am4_per_rst_map[] = {
441*e2ad626fSUlf Hansson 	{ .rst = 1, .st = 0 },
442*e2ad626fSUlf Hansson 	{ .rst = -1 },
443*e2ad626fSUlf Hansson };
444*e2ad626fSUlf Hansson 
445*e2ad626fSUlf Hansson static const struct omap_rst_map am4_device_rst_map[] = {
446*e2ad626fSUlf Hansson 	{ .rst = 0, .st = 1 },
447*e2ad626fSUlf Hansson 	{ .rst = 1, .st = 0 },
448*e2ad626fSUlf Hansson 	{ .rst = -1 },
449*e2ad626fSUlf Hansson };
450*e2ad626fSUlf Hansson 
451*e2ad626fSUlf Hansson static const struct omap_prm_data am4_prm_data[] = {
452*e2ad626fSUlf Hansson 	{
453*e2ad626fSUlf Hansson 		.name = "mpu", .base = 0x44df0300,
454*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
455*e2ad626fSUlf Hansson 	},
456*e2ad626fSUlf Hansson 	{
457*e2ad626fSUlf Hansson 		.name = "gfx", .base = 0x44df0400,
458*e2ad626fSUlf Hansson 		.pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
459*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
460*e2ad626fSUlf Hansson 	},
461*e2ad626fSUlf Hansson 	{
462*e2ad626fSUlf Hansson 		.name = "rtc", .base = 0x44df0500,
463*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
464*e2ad626fSUlf Hansson 	},
465*e2ad626fSUlf Hansson 	{
466*e2ad626fSUlf Hansson 		.name = "tamper", .base = 0x44df0600,
467*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
468*e2ad626fSUlf Hansson 	},
469*e2ad626fSUlf Hansson 	{
470*e2ad626fSUlf Hansson 		.name = "cefuse", .base = 0x44df0700,
471*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
472*e2ad626fSUlf Hansson 	},
473*e2ad626fSUlf Hansson 	{
474*e2ad626fSUlf Hansson 		.name = "per", .base = 0x44df0800,
475*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
476*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map,
477*e2ad626fSUlf Hansson 		.clkdm_name = "pruss_ocp"
478*e2ad626fSUlf Hansson 	},
479*e2ad626fSUlf Hansson 	{
480*e2ad626fSUlf Hansson 		.name = "wkup", .base = 0x44df2000,
481*e2ad626fSUlf Hansson 		.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
482*e2ad626fSUlf Hansson 		.rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map,
483*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_HAS_NO_CLKDM
484*e2ad626fSUlf Hansson 	},
485*e2ad626fSUlf Hansson 	{
486*e2ad626fSUlf Hansson 		.name = "device", .base = 0x44df4000,
487*e2ad626fSUlf Hansson 		.rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map,
488*e2ad626fSUlf Hansson 		.flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
489*e2ad626fSUlf Hansson 	},
490*e2ad626fSUlf Hansson 	{ },
491*e2ad626fSUlf Hansson };
492*e2ad626fSUlf Hansson 
493*e2ad626fSUlf Hansson static const struct of_device_id omap_prm_id_table[] = {
494*e2ad626fSUlf Hansson 	{ .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data },
495*e2ad626fSUlf Hansson 	{ .compatible = "ti,omap5-prm-inst", .data = omap5_prm_data },
496*e2ad626fSUlf Hansson 	{ .compatible = "ti,dra7-prm-inst", .data = dra7_prm_data },
497*e2ad626fSUlf Hansson 	{ .compatible = "ti,am3-prm-inst", .data = am3_prm_data },
498*e2ad626fSUlf Hansson 	{ .compatible = "ti,am4-prm-inst", .data = am4_prm_data },
499*e2ad626fSUlf Hansson 	{ },
500*e2ad626fSUlf Hansson };
501*e2ad626fSUlf Hansson 
502*e2ad626fSUlf Hansson #ifdef DEBUG
503*e2ad626fSUlf Hansson static void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
504*e2ad626fSUlf Hansson 				       const char *desc)
505*e2ad626fSUlf Hansson {
506*e2ad626fSUlf Hansson 	dev_dbg(prmd->dev, "%s %s: %08x/%08x\n",
507*e2ad626fSUlf Hansson 		prmd->pd.name, desc,
508*e2ad626fSUlf Hansson 		readl_relaxed(prmd->prm->base + prmd->pwrstctrl),
509*e2ad626fSUlf Hansson 		readl_relaxed(prmd->prm->base + prmd->pwrstst));
510*e2ad626fSUlf Hansson }
511*e2ad626fSUlf Hansson #else
512*e2ad626fSUlf Hansson static inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
513*e2ad626fSUlf Hansson 					      const char *desc)
514*e2ad626fSUlf Hansson {
515*e2ad626fSUlf Hansson }
516*e2ad626fSUlf Hansson #endif
517*e2ad626fSUlf Hansson 
518*e2ad626fSUlf Hansson static int omap_prm_domain_power_on(struct generic_pm_domain *domain)
519*e2ad626fSUlf Hansson {
520*e2ad626fSUlf Hansson 	struct omap_prm_domain *prmd;
521*e2ad626fSUlf Hansson 	int ret;
522*e2ad626fSUlf Hansson 	u32 v, mode;
523*e2ad626fSUlf Hansson 
524*e2ad626fSUlf Hansson 	prmd = genpd_to_prm_domain(domain);
525*e2ad626fSUlf Hansson 	if (!prmd->cap)
526*e2ad626fSUlf Hansson 		return 0;
527*e2ad626fSUlf Hansson 
528*e2ad626fSUlf Hansson 	omap_prm_domain_show_state(prmd, "on: previous state");
529*e2ad626fSUlf Hansson 
530*e2ad626fSUlf Hansson 	if (prmd->pwrstctrl_saved)
531*e2ad626fSUlf Hansson 		v = prmd->pwrstctrl_saved;
532*e2ad626fSUlf Hansson 	else
533*e2ad626fSUlf Hansson 		v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
534*e2ad626fSUlf Hansson 
535*e2ad626fSUlf Hansson 	if (prmd->prm->data->flags & OMAP_PRM_RET_WHEN_IDLE)
536*e2ad626fSUlf Hansson 		mode = OMAP_PRMD_RETENTION;
537*e2ad626fSUlf Hansson 	else
538*e2ad626fSUlf Hansson 		mode = OMAP_PRMD_ON_ACTIVE;
539*e2ad626fSUlf Hansson 
540*e2ad626fSUlf Hansson 	writel_relaxed((v & ~PRM_POWERSTATE_MASK) | mode,
541*e2ad626fSUlf Hansson 		       prmd->prm->base + prmd->pwrstctrl);
542*e2ad626fSUlf Hansson 
543*e2ad626fSUlf Hansson 	/* wait for the transition bit to get cleared */
544*e2ad626fSUlf Hansson 	ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
545*e2ad626fSUlf Hansson 					 v, !(v & PRM_ST_INTRANSITION), 1,
546*e2ad626fSUlf Hansson 					 PRM_STATE_MAX_WAIT);
547*e2ad626fSUlf Hansson 	if (ret)
548*e2ad626fSUlf Hansson 		dev_err(prmd->dev, "%s: %s timed out\n",
549*e2ad626fSUlf Hansson 			prmd->pd.name, __func__);
550*e2ad626fSUlf Hansson 
551*e2ad626fSUlf Hansson 	omap_prm_domain_show_state(prmd, "on: new state");
552*e2ad626fSUlf Hansson 
553*e2ad626fSUlf Hansson 	return ret;
554*e2ad626fSUlf Hansson }
555*e2ad626fSUlf Hansson 
556*e2ad626fSUlf Hansson /* No need to check for holes in the mask for the lowest mode */
557*e2ad626fSUlf Hansson static int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd)
558*e2ad626fSUlf Hansson {
559*e2ad626fSUlf Hansson 	return __ffs(prmd->cap->usable_modes);
560*e2ad626fSUlf Hansson }
561*e2ad626fSUlf Hansson 
562*e2ad626fSUlf Hansson static int omap_prm_domain_power_off(struct generic_pm_domain *domain)
563*e2ad626fSUlf Hansson {
564*e2ad626fSUlf Hansson 	struct omap_prm_domain *prmd;
565*e2ad626fSUlf Hansson 	int ret;
566*e2ad626fSUlf Hansson 	u32 v;
567*e2ad626fSUlf Hansson 
568*e2ad626fSUlf Hansson 	prmd = genpd_to_prm_domain(domain);
569*e2ad626fSUlf Hansson 	if (!prmd->cap)
570*e2ad626fSUlf Hansson 		return 0;
571*e2ad626fSUlf Hansson 
572*e2ad626fSUlf Hansson 	omap_prm_domain_show_state(prmd, "off: previous state");
573*e2ad626fSUlf Hansson 
574*e2ad626fSUlf Hansson 	v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
575*e2ad626fSUlf Hansson 	prmd->pwrstctrl_saved = v;
576*e2ad626fSUlf Hansson 
577*e2ad626fSUlf Hansson 	v &= ~PRM_POWERSTATE_MASK;
578*e2ad626fSUlf Hansson 	v |= omap_prm_domain_find_lowest(prmd);
579*e2ad626fSUlf Hansson 
580*e2ad626fSUlf Hansson 	if (prmd->cap->statechange)
581*e2ad626fSUlf Hansson 		v |= PRM_LOWPOWERSTATECHANGE;
582*e2ad626fSUlf Hansson 	if (prmd->cap->logicretstate)
583*e2ad626fSUlf Hansson 		v &= ~PRM_LOGICRETSTATE;
584*e2ad626fSUlf Hansson 	else
585*e2ad626fSUlf Hansson 		v |= PRM_LOGICRETSTATE;
586*e2ad626fSUlf Hansson 
587*e2ad626fSUlf Hansson 	writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl);
588*e2ad626fSUlf Hansson 
589*e2ad626fSUlf Hansson 	/* wait for the transition bit to get cleared */
590*e2ad626fSUlf Hansson 	ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
591*e2ad626fSUlf Hansson 					 v, !(v & PRM_ST_INTRANSITION), 1,
592*e2ad626fSUlf Hansson 					 PRM_STATE_MAX_WAIT);
593*e2ad626fSUlf Hansson 	if (ret)
594*e2ad626fSUlf Hansson 		dev_warn(prmd->dev, "%s: %s timed out\n",
595*e2ad626fSUlf Hansson 			 __func__, prmd->pd.name);
596*e2ad626fSUlf Hansson 
597*e2ad626fSUlf Hansson 	omap_prm_domain_show_state(prmd, "off: new state");
598*e2ad626fSUlf Hansson 
599*e2ad626fSUlf Hansson 	return 0;
600*e2ad626fSUlf Hansson }
601*e2ad626fSUlf Hansson 
602*e2ad626fSUlf Hansson /*
603*e2ad626fSUlf Hansson  * Note that ti-sysc already manages the module clocks separately so
604*e2ad626fSUlf Hansson  * no need to manage those. Interconnect instances need clocks managed
605*e2ad626fSUlf Hansson  * for simple-pm-bus.
606*e2ad626fSUlf Hansson  */
607*e2ad626fSUlf Hansson static int omap_prm_domain_attach_clock(struct device *dev,
608*e2ad626fSUlf Hansson 					struct omap_prm_domain *prmd)
609*e2ad626fSUlf Hansson {
610*e2ad626fSUlf Hansson 	struct device_node *np = dev->of_node;
611*e2ad626fSUlf Hansson 	int error;
612*e2ad626fSUlf Hansson 
613*e2ad626fSUlf Hansson 	if (!of_device_is_compatible(np, "simple-pm-bus"))
614*e2ad626fSUlf Hansson 		return 0;
615*e2ad626fSUlf Hansson 
616*e2ad626fSUlf Hansson 	if (!of_property_read_bool(np, "clocks"))
617*e2ad626fSUlf Hansson 		return 0;
618*e2ad626fSUlf Hansson 
619*e2ad626fSUlf Hansson 	error = pm_clk_create(dev);
620*e2ad626fSUlf Hansson 	if (error)
621*e2ad626fSUlf Hansson 		return error;
622*e2ad626fSUlf Hansson 
623*e2ad626fSUlf Hansson 	error = of_pm_clk_add_clks(dev);
624*e2ad626fSUlf Hansson 	if (error < 0) {
625*e2ad626fSUlf Hansson 		pm_clk_destroy(dev);
626*e2ad626fSUlf Hansson 		return error;
627*e2ad626fSUlf Hansson 	}
628*e2ad626fSUlf Hansson 
629*e2ad626fSUlf Hansson 	prmd->uses_pm_clk = 1;
630*e2ad626fSUlf Hansson 
631*e2ad626fSUlf Hansson 	return 0;
632*e2ad626fSUlf Hansson }
633*e2ad626fSUlf Hansson 
634*e2ad626fSUlf Hansson static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain,
635*e2ad626fSUlf Hansson 				      struct device *dev)
636*e2ad626fSUlf Hansson {
637*e2ad626fSUlf Hansson 	struct generic_pm_domain_data *genpd_data;
638*e2ad626fSUlf Hansson 	struct of_phandle_args pd_args;
639*e2ad626fSUlf Hansson 	struct omap_prm_domain *prmd;
640*e2ad626fSUlf Hansson 	struct device_node *np;
641*e2ad626fSUlf Hansson 	int ret;
642*e2ad626fSUlf Hansson 
643*e2ad626fSUlf Hansson 	prmd = genpd_to_prm_domain(domain);
644*e2ad626fSUlf Hansson 	np = dev->of_node;
645*e2ad626fSUlf Hansson 
646*e2ad626fSUlf Hansson 	ret = of_parse_phandle_with_args(np, "power-domains",
647*e2ad626fSUlf Hansson 					 "#power-domain-cells", 0, &pd_args);
648*e2ad626fSUlf Hansson 	if (ret < 0)
649*e2ad626fSUlf Hansson 		return ret;
650*e2ad626fSUlf Hansson 
651*e2ad626fSUlf Hansson 	if (pd_args.args_count != 0)
652*e2ad626fSUlf Hansson 		dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n",
653*e2ad626fSUlf Hansson 			 prmd->pd.name, pd_args.args_count);
654*e2ad626fSUlf Hansson 
655*e2ad626fSUlf Hansson 	genpd_data = dev_gpd_data(dev);
656*e2ad626fSUlf Hansson 	genpd_data->data = NULL;
657*e2ad626fSUlf Hansson 
658*e2ad626fSUlf Hansson 	ret = omap_prm_domain_attach_clock(dev, prmd);
659*e2ad626fSUlf Hansson 	if (ret)
660*e2ad626fSUlf Hansson 		return ret;
661*e2ad626fSUlf Hansson 
662*e2ad626fSUlf Hansson 	return 0;
663*e2ad626fSUlf Hansson }
664*e2ad626fSUlf Hansson 
665*e2ad626fSUlf Hansson static void omap_prm_domain_detach_dev(struct generic_pm_domain *domain,
666*e2ad626fSUlf Hansson 				       struct device *dev)
667*e2ad626fSUlf Hansson {
668*e2ad626fSUlf Hansson 	struct generic_pm_domain_data *genpd_data;
669*e2ad626fSUlf Hansson 	struct omap_prm_domain *prmd;
670*e2ad626fSUlf Hansson 
671*e2ad626fSUlf Hansson 	prmd = genpd_to_prm_domain(domain);
672*e2ad626fSUlf Hansson 	if (prmd->uses_pm_clk)
673*e2ad626fSUlf Hansson 		pm_clk_destroy(dev);
674*e2ad626fSUlf Hansson 	genpd_data = dev_gpd_data(dev);
675*e2ad626fSUlf Hansson 	genpd_data->data = NULL;
676*e2ad626fSUlf Hansson }
677*e2ad626fSUlf Hansson 
678*e2ad626fSUlf Hansson static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm)
679*e2ad626fSUlf Hansson {
680*e2ad626fSUlf Hansson 	struct omap_prm_domain *prmd;
681*e2ad626fSUlf Hansson 	struct device_node *np = dev->of_node;
682*e2ad626fSUlf Hansson 	const struct omap_prm_data *data;
683*e2ad626fSUlf Hansson 	const char *name;
684*e2ad626fSUlf Hansson 	int error;
685*e2ad626fSUlf Hansson 
686*e2ad626fSUlf Hansson 	if (!of_property_present(dev->of_node, "#power-domain-cells"))
687*e2ad626fSUlf Hansson 		return 0;
688*e2ad626fSUlf Hansson 
689*e2ad626fSUlf Hansson 	of_node_put(dev->of_node);
690*e2ad626fSUlf Hansson 
691*e2ad626fSUlf Hansson 	prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL);
692*e2ad626fSUlf Hansson 	if (!prmd)
693*e2ad626fSUlf Hansson 		return -ENOMEM;
694*e2ad626fSUlf Hansson 
695*e2ad626fSUlf Hansson 	data = prm->data;
696*e2ad626fSUlf Hansson 	name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s",
697*e2ad626fSUlf Hansson 			      data->name);
698*e2ad626fSUlf Hansson 
699*e2ad626fSUlf Hansson 	prmd->dev = dev;
700*e2ad626fSUlf Hansson 	prmd->prm = prm;
701*e2ad626fSUlf Hansson 	prmd->cap = prmd->prm->data->dmap;
702*e2ad626fSUlf Hansson 	prmd->pwrstctrl = prmd->prm->data->pwrstctrl;
703*e2ad626fSUlf Hansson 	prmd->pwrstst = prmd->prm->data->pwrstst;
704*e2ad626fSUlf Hansson 
705*e2ad626fSUlf Hansson 	prmd->pd.name = name;
706*e2ad626fSUlf Hansson 	prmd->pd.power_on = omap_prm_domain_power_on;
707*e2ad626fSUlf Hansson 	prmd->pd.power_off = omap_prm_domain_power_off;
708*e2ad626fSUlf Hansson 	prmd->pd.attach_dev = omap_prm_domain_attach_dev;
709*e2ad626fSUlf Hansson 	prmd->pd.detach_dev = omap_prm_domain_detach_dev;
710*e2ad626fSUlf Hansson 	prmd->pd.flags = GENPD_FLAG_PM_CLK;
711*e2ad626fSUlf Hansson 
712*e2ad626fSUlf Hansson 	pm_genpd_init(&prmd->pd, NULL, true);
713*e2ad626fSUlf Hansson 	error = of_genpd_add_provider_simple(np, &prmd->pd);
714*e2ad626fSUlf Hansson 	if (error)
715*e2ad626fSUlf Hansson 		pm_genpd_remove(&prmd->pd);
716*e2ad626fSUlf Hansson 	else
717*e2ad626fSUlf Hansson 		prm->prmd = prmd;
718*e2ad626fSUlf Hansson 
719*e2ad626fSUlf Hansson 	return error;
720*e2ad626fSUlf Hansson }
721*e2ad626fSUlf Hansson 
722*e2ad626fSUlf Hansson static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id)
723*e2ad626fSUlf Hansson {
724*e2ad626fSUlf Hansson 	if (reset->mask & BIT(id))
725*e2ad626fSUlf Hansson 		return true;
726*e2ad626fSUlf Hansson 
727*e2ad626fSUlf Hansson 	return false;
728*e2ad626fSUlf Hansson }
729*e2ad626fSUlf Hansson 
730*e2ad626fSUlf Hansson static int omap_reset_get_st_bit(struct omap_reset_data *reset,
731*e2ad626fSUlf Hansson 				 unsigned long id)
732*e2ad626fSUlf Hansson {
733*e2ad626fSUlf Hansson 	const struct omap_rst_map *map = reset->prm->data->rstmap;
734*e2ad626fSUlf Hansson 
735*e2ad626fSUlf Hansson 	while (map->rst >= 0) {
736*e2ad626fSUlf Hansson 		if (map->rst == id)
737*e2ad626fSUlf Hansson 			return map->st;
738*e2ad626fSUlf Hansson 
739*e2ad626fSUlf Hansson 		map++;
740*e2ad626fSUlf Hansson 	}
741*e2ad626fSUlf Hansson 
742*e2ad626fSUlf Hansson 	return id;
743*e2ad626fSUlf Hansson }
744*e2ad626fSUlf Hansson 
745*e2ad626fSUlf Hansson static int omap_reset_status(struct reset_controller_dev *rcdev,
746*e2ad626fSUlf Hansson 			     unsigned long id)
747*e2ad626fSUlf Hansson {
748*e2ad626fSUlf Hansson 	struct omap_reset_data *reset = to_omap_reset_data(rcdev);
749*e2ad626fSUlf Hansson 	u32 v;
750*e2ad626fSUlf Hansson 	int st_bit = omap_reset_get_st_bit(reset, id);
751*e2ad626fSUlf Hansson 	bool has_rstst = reset->prm->data->rstst ||
752*e2ad626fSUlf Hansson 		(reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
753*e2ad626fSUlf Hansson 
754*e2ad626fSUlf Hansson 	/* Check if we have rstst */
755*e2ad626fSUlf Hansson 	if (!has_rstst)
756*e2ad626fSUlf Hansson 		return -ENOTSUPP;
757*e2ad626fSUlf Hansson 
758*e2ad626fSUlf Hansson 	/* Check if hw reset line is asserted */
759*e2ad626fSUlf Hansson 	v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
760*e2ad626fSUlf Hansson 	if (v & BIT(id))
761*e2ad626fSUlf Hansson 		return 1;
762*e2ad626fSUlf Hansson 
763*e2ad626fSUlf Hansson 	/*
764*e2ad626fSUlf Hansson 	 * Check reset status, high value means reset sequence has been
765*e2ad626fSUlf Hansson 	 * completed successfully so we can return 0 here (reset deasserted)
766*e2ad626fSUlf Hansson 	 */
767*e2ad626fSUlf Hansson 	v = readl_relaxed(reset->prm->base + reset->prm->data->rstst);
768*e2ad626fSUlf Hansson 	v >>= st_bit;
769*e2ad626fSUlf Hansson 	v &= 1;
770*e2ad626fSUlf Hansson 
771*e2ad626fSUlf Hansson 	return !v;
772*e2ad626fSUlf Hansson }
773*e2ad626fSUlf Hansson 
774*e2ad626fSUlf Hansson static int omap_reset_assert(struct reset_controller_dev *rcdev,
775*e2ad626fSUlf Hansson 			     unsigned long id)
776*e2ad626fSUlf Hansson {
777*e2ad626fSUlf Hansson 	struct omap_reset_data *reset = to_omap_reset_data(rcdev);
778*e2ad626fSUlf Hansson 	u32 v;
779*e2ad626fSUlf Hansson 	unsigned long flags;
780*e2ad626fSUlf Hansson 
781*e2ad626fSUlf Hansson 	/* assert the reset control line */
782*e2ad626fSUlf Hansson 	spin_lock_irqsave(&reset->lock, flags);
783*e2ad626fSUlf Hansson 	v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
784*e2ad626fSUlf Hansson 	v |= 1 << id;
785*e2ad626fSUlf Hansson 	writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
786*e2ad626fSUlf Hansson 	spin_unlock_irqrestore(&reset->lock, flags);
787*e2ad626fSUlf Hansson 
788*e2ad626fSUlf Hansson 	return 0;
789*e2ad626fSUlf Hansson }
790*e2ad626fSUlf Hansson 
791*e2ad626fSUlf Hansson static int omap_reset_deassert(struct reset_controller_dev *rcdev,
792*e2ad626fSUlf Hansson 			       unsigned long id)
793*e2ad626fSUlf Hansson {
794*e2ad626fSUlf Hansson 	struct omap_reset_data *reset = to_omap_reset_data(rcdev);
795*e2ad626fSUlf Hansson 	u32 v;
796*e2ad626fSUlf Hansson 	int st_bit;
797*e2ad626fSUlf Hansson 	bool has_rstst;
798*e2ad626fSUlf Hansson 	unsigned long flags;
799*e2ad626fSUlf Hansson 	struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev);
800*e2ad626fSUlf Hansson 	int ret = 0;
801*e2ad626fSUlf Hansson 
802*e2ad626fSUlf Hansson 	/* Nothing to do if the reset is already deasserted */
803*e2ad626fSUlf Hansson 	if (!omap_reset_status(rcdev, id))
804*e2ad626fSUlf Hansson 		return 0;
805*e2ad626fSUlf Hansson 
806*e2ad626fSUlf Hansson 	has_rstst = reset->prm->data->rstst ||
807*e2ad626fSUlf Hansson 		(reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
808*e2ad626fSUlf Hansson 
809*e2ad626fSUlf Hansson 	if (has_rstst) {
810*e2ad626fSUlf Hansson 		st_bit = omap_reset_get_st_bit(reset, id);
811*e2ad626fSUlf Hansson 
812*e2ad626fSUlf Hansson 		/* Clear the reset status by writing 1 to the status bit */
813*e2ad626fSUlf Hansson 		v = 1 << st_bit;
814*e2ad626fSUlf Hansson 		writel_relaxed(v, reset->prm->base + reset->prm->data->rstst);
815*e2ad626fSUlf Hansson 	}
816*e2ad626fSUlf Hansson 
817*e2ad626fSUlf Hansson 	if (reset->clkdm)
818*e2ad626fSUlf Hansson 		pdata->clkdm_deny_idle(reset->clkdm);
819*e2ad626fSUlf Hansson 
820*e2ad626fSUlf Hansson 	/* de-assert the reset control line */
821*e2ad626fSUlf Hansson 	spin_lock_irqsave(&reset->lock, flags);
822*e2ad626fSUlf Hansson 	v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
823*e2ad626fSUlf Hansson 	v &= ~(1 << id);
824*e2ad626fSUlf Hansson 	writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
825*e2ad626fSUlf Hansson 	spin_unlock_irqrestore(&reset->lock, flags);
826*e2ad626fSUlf Hansson 
827*e2ad626fSUlf Hansson 	/* wait for the reset bit to clear */
828*e2ad626fSUlf Hansson 	ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
829*e2ad626fSUlf Hansson 						reset->prm->data->rstctrl,
830*e2ad626fSUlf Hansson 						v, !(v & BIT(id)), 1,
831*e2ad626fSUlf Hansson 						OMAP_RESET_MAX_WAIT);
832*e2ad626fSUlf Hansson 	if (ret)
833*e2ad626fSUlf Hansson 		pr_err("%s: timedout waiting for %s:%lu\n", __func__,
834*e2ad626fSUlf Hansson 		       reset->prm->data->name, id);
835*e2ad626fSUlf Hansson 
836*e2ad626fSUlf Hansson 	/* wait for the status to be set */
837*e2ad626fSUlf Hansson 	if (has_rstst) {
838*e2ad626fSUlf Hansson 		ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
839*e2ad626fSUlf Hansson 						 reset->prm->data->rstst,
840*e2ad626fSUlf Hansson 						 v, v & BIT(st_bit), 1,
841*e2ad626fSUlf Hansson 						 OMAP_RESET_MAX_WAIT);
842*e2ad626fSUlf Hansson 		if (ret)
843*e2ad626fSUlf Hansson 			pr_err("%s: timedout waiting for %s:%lu\n", __func__,
844*e2ad626fSUlf Hansson 			       reset->prm->data->name, id);
845*e2ad626fSUlf Hansson 	}
846*e2ad626fSUlf Hansson 
847*e2ad626fSUlf Hansson 	if (reset->clkdm)
848*e2ad626fSUlf Hansson 		pdata->clkdm_allow_idle(reset->clkdm);
849*e2ad626fSUlf Hansson 
850*e2ad626fSUlf Hansson 	return ret;
851*e2ad626fSUlf Hansson }
852*e2ad626fSUlf Hansson 
853*e2ad626fSUlf Hansson static const struct reset_control_ops omap_reset_ops = {
854*e2ad626fSUlf Hansson 	.assert		= omap_reset_assert,
855*e2ad626fSUlf Hansson 	.deassert	= omap_reset_deassert,
856*e2ad626fSUlf Hansson 	.status		= omap_reset_status,
857*e2ad626fSUlf Hansson };
858*e2ad626fSUlf Hansson 
859*e2ad626fSUlf Hansson static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev,
860*e2ad626fSUlf Hansson 				const struct of_phandle_args *reset_spec)
861*e2ad626fSUlf Hansson {
862*e2ad626fSUlf Hansson 	struct omap_reset_data *reset = to_omap_reset_data(rcdev);
863*e2ad626fSUlf Hansson 
864*e2ad626fSUlf Hansson 	if (!_is_valid_reset(reset, reset_spec->args[0]))
865*e2ad626fSUlf Hansson 		return -EINVAL;
866*e2ad626fSUlf Hansson 
867*e2ad626fSUlf Hansson 	return reset_spec->args[0];
868*e2ad626fSUlf Hansson }
869*e2ad626fSUlf Hansson 
870*e2ad626fSUlf Hansson static int omap_prm_reset_init(struct platform_device *pdev,
871*e2ad626fSUlf Hansson 			       struct omap_prm *prm)
872*e2ad626fSUlf Hansson {
873*e2ad626fSUlf Hansson 	struct omap_reset_data *reset;
874*e2ad626fSUlf Hansson 	const struct omap_rst_map *map;
875*e2ad626fSUlf Hansson 	struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev);
876*e2ad626fSUlf Hansson 	char buf[32];
877*e2ad626fSUlf Hansson 	u32 v;
878*e2ad626fSUlf Hansson 
879*e2ad626fSUlf Hansson 	/*
880*e2ad626fSUlf Hansson 	 * Check if we have controllable resets. If either rstctrl is non-zero
881*e2ad626fSUlf Hansson 	 * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
882*e2ad626fSUlf Hansson 	 * for the domain.
883*e2ad626fSUlf Hansson 	 */
884*e2ad626fSUlf Hansson 	if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL))
885*e2ad626fSUlf Hansson 		return 0;
886*e2ad626fSUlf Hansson 
887*e2ad626fSUlf Hansson 	/* Check if we have the pdata callbacks in place */
888*e2ad626fSUlf Hansson 	if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle ||
889*e2ad626fSUlf Hansson 	    !pdata->clkdm_allow_idle)
890*e2ad626fSUlf Hansson 		return -EINVAL;
891*e2ad626fSUlf Hansson 
892*e2ad626fSUlf Hansson 	map = prm->data->rstmap;
893*e2ad626fSUlf Hansson 	if (!map)
894*e2ad626fSUlf Hansson 		return -EINVAL;
895*e2ad626fSUlf Hansson 
896*e2ad626fSUlf Hansson 	reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
897*e2ad626fSUlf Hansson 	if (!reset)
898*e2ad626fSUlf Hansson 		return -ENOMEM;
899*e2ad626fSUlf Hansson 
900*e2ad626fSUlf Hansson 	reset->rcdev.owner = THIS_MODULE;
901*e2ad626fSUlf Hansson 	reset->rcdev.ops = &omap_reset_ops;
902*e2ad626fSUlf Hansson 	reset->rcdev.of_node = pdev->dev.of_node;
903*e2ad626fSUlf Hansson 	reset->rcdev.nr_resets = OMAP_MAX_RESETS;
904*e2ad626fSUlf Hansson 	reset->rcdev.of_xlate = omap_prm_reset_xlate;
905*e2ad626fSUlf Hansson 	reset->rcdev.of_reset_n_cells = 1;
906*e2ad626fSUlf Hansson 	reset->dev = &pdev->dev;
907*e2ad626fSUlf Hansson 	spin_lock_init(&reset->lock);
908*e2ad626fSUlf Hansson 
909*e2ad626fSUlf Hansson 	reset->prm = prm;
910*e2ad626fSUlf Hansson 
911*e2ad626fSUlf Hansson 	sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name :
912*e2ad626fSUlf Hansson 		prm->data->name);
913*e2ad626fSUlf Hansson 
914*e2ad626fSUlf Hansson 	if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) {
915*e2ad626fSUlf Hansson 		reset->clkdm = pdata->clkdm_lookup(buf);
916*e2ad626fSUlf Hansson 		if (!reset->clkdm)
917*e2ad626fSUlf Hansson 			return -EINVAL;
918*e2ad626fSUlf Hansson 	}
919*e2ad626fSUlf Hansson 
920*e2ad626fSUlf Hansson 	while (map->rst >= 0) {
921*e2ad626fSUlf Hansson 		reset->mask |= BIT(map->rst);
922*e2ad626fSUlf Hansson 		map++;
923*e2ad626fSUlf Hansson 	}
924*e2ad626fSUlf Hansson 
925*e2ad626fSUlf Hansson 	/* Quirk handling to assert rst_map_012 bits on reset and avoid errors */
926*e2ad626fSUlf Hansson 	if (prm->data->rstmap == rst_map_012) {
927*e2ad626fSUlf Hansson 		v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
928*e2ad626fSUlf Hansson 		if ((v & reset->mask) != reset->mask) {
929*e2ad626fSUlf Hansson 			dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v);
930*e2ad626fSUlf Hansson 			writel_relaxed(reset->mask, reset->prm->base +
931*e2ad626fSUlf Hansson 				       reset->prm->data->rstctrl);
932*e2ad626fSUlf Hansson 		}
933*e2ad626fSUlf Hansson 	}
934*e2ad626fSUlf Hansson 
935*e2ad626fSUlf Hansson 	return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
936*e2ad626fSUlf Hansson }
937*e2ad626fSUlf Hansson 
938*e2ad626fSUlf Hansson static int omap_prm_probe(struct platform_device *pdev)
939*e2ad626fSUlf Hansson {
940*e2ad626fSUlf Hansson 	struct resource *res;
941*e2ad626fSUlf Hansson 	const struct omap_prm_data *data;
942*e2ad626fSUlf Hansson 	struct omap_prm *prm;
943*e2ad626fSUlf Hansson 	int ret;
944*e2ad626fSUlf Hansson 
945*e2ad626fSUlf Hansson 	data = of_device_get_match_data(&pdev->dev);
946*e2ad626fSUlf Hansson 	if (!data)
947*e2ad626fSUlf Hansson 		return -ENOTSUPP;
948*e2ad626fSUlf Hansson 
949*e2ad626fSUlf Hansson 	prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL);
950*e2ad626fSUlf Hansson 	if (!prm)
951*e2ad626fSUlf Hansson 		return -ENOMEM;
952*e2ad626fSUlf Hansson 
953*e2ad626fSUlf Hansson 	prm->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
954*e2ad626fSUlf Hansson 	if (IS_ERR(prm->base))
955*e2ad626fSUlf Hansson 		return PTR_ERR(prm->base);
956*e2ad626fSUlf Hansson 
957*e2ad626fSUlf Hansson 	while (data->base != res->start) {
958*e2ad626fSUlf Hansson 		if (!data->base)
959*e2ad626fSUlf Hansson 			return -EINVAL;
960*e2ad626fSUlf Hansson 		data++;
961*e2ad626fSUlf Hansson 	}
962*e2ad626fSUlf Hansson 
963*e2ad626fSUlf Hansson 	prm->data = data;
964*e2ad626fSUlf Hansson 
965*e2ad626fSUlf Hansson 	ret = omap_prm_domain_init(&pdev->dev, prm);
966*e2ad626fSUlf Hansson 	if (ret)
967*e2ad626fSUlf Hansson 		return ret;
968*e2ad626fSUlf Hansson 
969*e2ad626fSUlf Hansson 	ret = omap_prm_reset_init(pdev, prm);
970*e2ad626fSUlf Hansson 	if (ret)
971*e2ad626fSUlf Hansson 		goto err_domain;
972*e2ad626fSUlf Hansson 
973*e2ad626fSUlf Hansson 	return 0;
974*e2ad626fSUlf Hansson 
975*e2ad626fSUlf Hansson err_domain:
976*e2ad626fSUlf Hansson 	of_genpd_del_provider(pdev->dev.of_node);
977*e2ad626fSUlf Hansson 	pm_genpd_remove(&prm->prmd->pd);
978*e2ad626fSUlf Hansson 
979*e2ad626fSUlf Hansson 	return ret;
980*e2ad626fSUlf Hansson }
981*e2ad626fSUlf Hansson 
982*e2ad626fSUlf Hansson static struct platform_driver omap_prm_driver = {
983*e2ad626fSUlf Hansson 	.probe = omap_prm_probe,
984*e2ad626fSUlf Hansson 	.driver = {
985*e2ad626fSUlf Hansson 		.name		= KBUILD_MODNAME,
986*e2ad626fSUlf Hansson 		.of_match_table	= omap_prm_id_table,
987*e2ad626fSUlf Hansson 	},
988*e2ad626fSUlf Hansson };
989*e2ad626fSUlf Hansson builtin_platform_driver(omap_prm_driver);
990