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