Linux Audio

Check our new training course

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