1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Tero Kristo <t-kristo@ti.com>
9 #include <linux/kernel.h>
10 #include <linux/clk.h>
11 #include <linux/device.h>
13 #include <linux/iopoll.h>
14 #include <linux/module.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>
23 #include <linux/platform_data/ti-prm.h>
25 enum omap_prm_domain_mode
{
28 OMAP_PRMD_ON_INACTIVE
,
32 struct 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 */
38 struct omap_prm_domain
{
41 struct generic_pm_domain pd
;
44 const struct omap_prm_domain_map
*cap
;
46 unsigned int uses_pm_clk
:1;
54 struct omap_prm_data
{
57 const char *clkdm_name
;
60 const struct omap_prm_domain_map
*dmap
;
63 const struct omap_rst_map
*rstmap
;
68 const struct omap_prm_data
*data
;
70 struct omap_prm_domain
*prmd
;
73 struct omap_reset_data
{
74 struct reset_controller_dev rcdev
;
78 struct clockdomain
*clkdm
;
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)
85 #define OMAP_MAX_RESETS 8
86 #define OMAP_RESET_MAX_WAIT 10000
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)
92 #define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
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
99 #define PRM_ST_INTRANSITION BIT(20)
101 static 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
),
108 static const struct omap_prm_domain_map omap_prm_noinact
= {
109 .usable_modes
= BIT(OMAP_PRMD_ON_ACTIVE
) | BIT(OMAP_PRMD_RETENTION
) |
115 static 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
),
122 static const struct omap_prm_domain_map omap_prm_onoff_noauto
= {
123 .usable_modes
= BIT(OMAP_PRMD_ON_ACTIVE
) | BIT(OMAP_PRMD_OFF
),
127 static const struct omap_prm_domain_map omap_prm_alwon
= {
128 .usable_modes
= BIT(OMAP_PRMD_ON_ACTIVE
),
131 static const struct omap_prm_domain_map omap_prm_reton
= {
132 .usable_modes
= BIT(OMAP_PRMD_ON_ACTIVE
) | BIT(OMAP_PRMD_RETENTION
),
137 static const struct omap_rst_map rst_map_0
[] = {
138 { .rst
= 0, .st
= 0 },
142 static const struct omap_rst_map rst_map_01
[] = {
143 { .rst
= 0, .st
= 0 },
144 { .rst
= 1, .st
= 1 },
148 static const struct omap_rst_map rst_map_012
[] = {
149 { .rst
= 0, .st
= 0 },
150 { .rst
= 1, .st
= 1 },
151 { .rst
= 2, .st
= 2 },
155 static const struct omap_prm_data omap4_prm_data
[] = {
157 .name
= "mpu", .base
= 0x4a306300,
158 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_reton
,
161 .name
= "tesla", .base
= 0x4a306400,
162 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
,
163 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
166 .name
= "abe", .base
= 0x4a306500,
167 .pwrstctrl
= 0, .pwrstst
= 0x4, .dmap
= &omap_prm_all
,
170 .name
= "always_on_core", .base
= 0x4a306600,
171 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
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
180 .name
= "ivahd", .base
= 0x4a306f00,
181 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
,
182 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_012
185 .name
= "cam", .base
= 0x4a307000,
186 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
189 .name
= "dss", .base
= 0x4a307100,
190 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
193 .name
= "gfx", .base
= 0x4a307200,
194 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
197 .name
= "l3init", .base
= 0x4a307300,
198 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_reton
201 .name
= "l4per", .base
= 0x4a307400,
202 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_reton
205 .name
= "cefuse", .base
= 0x4a307600,
206 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
209 .name
= "wkup", .base
= 0x4a307700,
210 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
213 .name
= "emu", .base
= 0x4a307900,
214 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
217 .name
= "device", .base
= 0x4a307b00,
218 .rstctrl
= 0x0, .rstst
= 0x4, .rstmap
= rst_map_01
,
219 .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
224 static const struct omap_prm_data omap5_prm_data
[] = {
226 .name
= "mpu", .base
= 0x4ae06300,
227 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_reton
,
230 .name
= "dsp", .base
= 0x4ae06400,
231 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
,
232 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
235 .name
= "abe", .base
= 0x4ae06500,
236 .pwrstctrl
= 0, .pwrstst
= 0x4, .dmap
= &omap_prm_nooff
,
239 .name
= "coreaon", .base
= 0x4ae06600,
240 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
243 .name
= "core", .base
= 0x4ae06700,
244 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_reton
,
245 .rstctrl
= 0x210, .rstst
= 0x214, .clkdm_name
= "ipu",
246 .rstmap
= rst_map_012
249 .name
= "iva", .base
= 0x4ae07200,
250 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
,
251 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_012
254 .name
= "cam", .base
= 0x4ae07300,
255 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
258 .name
= "dss", .base
= 0x4ae07400,
259 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
262 .name
= "gpu", .base
= 0x4ae07500,
263 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
266 .name
= "l3init", .base
= 0x4ae07600,
267 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_reton
270 .name
= "custefuse", .base
= 0x4ae07700,
271 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
274 .name
= "wkupaon", .base
= 0x4ae07800,
275 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
278 .name
= "emu", .base
= 0x4ae07a00,
279 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
282 .name
= "device", .base
= 0x4ae07c00,
283 .rstctrl
= 0x0, .rstst
= 0x4, .rstmap
= rst_map_01
,
284 .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
289 static const struct omap_prm_data dra7_prm_data
[] = {
291 .name
= "mpu", .base
= 0x4ae06300,
292 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_reton
,
295 .name
= "dsp1", .base
= 0x4ae06400,
296 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
297 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
,
300 .name
= "ipu", .base
= 0x4ae06500,
301 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
302 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_012
,
306 .name
= "coreaon", .base
= 0x4ae06628,
307 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
310 .name
= "core", .base
= 0x4ae06700,
311 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
312 .rstctrl
= 0x210, .rstst
= 0x214, .rstmap
= rst_map_012
,
316 .name
= "iva", .base
= 0x4ae06f00,
317 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
318 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_012
,
321 .name
= "cam", .base
= 0x4ae07000,
322 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
325 .name
= "dss", .base
= 0x4ae07100,
326 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
329 .name
= "gpu", .base
= 0x4ae07200,
330 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
333 .name
= "l3init", .base
= 0x4ae07300,
334 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
335 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_012
,
339 .name
= "l4per", .base
= 0x4ae07400,
340 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
343 .name
= "custefuse", .base
= 0x4ae07600,
344 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
347 .name
= "wkupaon", .base
= 0x4ae07724,
348 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
351 .name
= "emu", .base
= 0x4ae07900,
352 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
355 .name
= "dsp2", .base
= 0x4ae07b00,
356 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
357 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
360 .name
= "eve1", .base
= 0x4ae07b40,
361 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
362 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
365 .name
= "eve2", .base
= 0x4ae07b80,
366 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
367 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
370 .name
= "eve3", .base
= 0x4ae07bc0,
371 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
372 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
375 .name
= "eve4", .base
= 0x4ae07c00,
376 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
377 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
380 .name
= "rtc", .base
= 0x4ae07c60,
381 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
384 .name
= "vpe", .base
= 0x4ae07c80,
385 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
390 static const struct omap_rst_map am3_per_rst_map
[] = {
395 static const struct omap_rst_map am3_wkup_rst_map
[] = {
396 { .rst
= 3, .st
= 5 },
400 static const struct omap_prm_data am3_prm_data
[] = {
402 .name
= "per", .base
= 0x44e00c00,
403 .pwrstctrl
= 0xc, .pwrstst
= 0x8, .dmap
= &omap_prm_noinact
,
404 .rstctrl
= 0x0, .rstmap
= am3_per_rst_map
,
405 .flags
= OMAP_PRM_HAS_RSTCTRL
, .clkdm_name
= "pruss_ocp"
408 .name
= "wkup", .base
= 0x44e00d00,
409 .pwrstctrl
= 0x4, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
410 .rstctrl
= 0x0, .rstst
= 0xc, .rstmap
= am3_wkup_rst_map
,
411 .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
414 .name
= "mpu", .base
= 0x44e00e00,
415 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
,
418 .name
= "device", .base
= 0x44e00f00,
419 .rstctrl
= 0x0, .rstst
= 0x8, .rstmap
= rst_map_01
,
420 .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
423 .name
= "rtc", .base
= 0x44e01000,
424 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
427 .name
= "gfx", .base
= 0x44e01100,
428 .pwrstctrl
= 0, .pwrstst
= 0x10, .dmap
= &omap_prm_noinact
,
429 .rstctrl
= 0x4, .rstst
= 0x14, .rstmap
= rst_map_0
, .clkdm_name
= "gfx_l3",
432 .name
= "cefuse", .base
= 0x44e01200,
433 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
438 static const struct omap_rst_map am4_per_rst_map
[] = {
439 { .rst
= 1, .st
= 0 },
443 static const struct omap_rst_map am4_device_rst_map
[] = {
444 { .rst
= 0, .st
= 1 },
445 { .rst
= 1, .st
= 0 },
449 static const struct omap_prm_data am4_prm_data
[] = {
451 .name
= "mpu", .base
= 0x44df0300,
452 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
,
455 .name
= "gfx", .base
= 0x44df0400,
456 .pwrstctrl
= 0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
457 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_0
, .clkdm_name
= "gfx_l3",
460 .name
= "rtc", .base
= 0x44df0500,
461 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
464 .name
= "tamper", .base
= 0x44df0600,
465 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
468 .name
= "cefuse", .base
= 0x44df0700,
469 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_onoff_noauto
,
472 .name
= "per", .base
= 0x44df0800,
473 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_noinact
,
474 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= am4_per_rst_map
,
475 .clkdm_name
= "pruss_ocp"
478 .name
= "wkup", .base
= 0x44df2000,
479 .pwrstctrl
= 0x0, .pwrstst
= 0x4, .dmap
= &omap_prm_alwon
,
480 .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= am3_wkup_rst_map
,
481 .flags
= OMAP_PRM_HAS_NO_CLKDM
484 .name
= "device", .base
= 0x44df4000,
485 .rstctrl
= 0x0, .rstst
= 0x4, .rstmap
= am4_device_rst_map
,
486 .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
491 static const struct of_device_id omap_prm_id_table
[] = {
492 { .compatible
= "ti,omap4-prm-inst", .data
= omap4_prm_data
},
493 { .compatible
= "ti,omap5-prm-inst", .data
= omap5_prm_data
},
494 { .compatible
= "ti,dra7-prm-inst", .data
= dra7_prm_data
},
495 { .compatible
= "ti,am3-prm-inst", .data
= am3_prm_data
},
496 { .compatible
= "ti,am4-prm-inst", .data
= am4_prm_data
},
501 static void omap_prm_domain_show_state(struct omap_prm_domain
*prmd
,
504 dev_dbg(prmd
->dev
, "%s %s: %08x/%08x\n",
506 readl_relaxed(prmd
->prm
->base
+ prmd
->pwrstctrl
),
507 readl_relaxed(prmd
->prm
->base
+ prmd
->pwrstst
));
510 static inline void omap_prm_domain_show_state(struct omap_prm_domain
*prmd
,
516 static int omap_prm_domain_power_on(struct generic_pm_domain
*domain
)
518 struct omap_prm_domain
*prmd
;
522 prmd
= genpd_to_prm_domain(domain
);
526 omap_prm_domain_show_state(prmd
, "on: previous state");
528 if (prmd
->pwrstctrl_saved
)
529 v
= prmd
->pwrstctrl_saved
;
531 v
= readl_relaxed(prmd
->prm
->base
+ prmd
->pwrstctrl
);
533 writel_relaxed(v
| OMAP_PRMD_ON_ACTIVE
,
534 prmd
->prm
->base
+ prmd
->pwrstctrl
);
536 /* wait for the transition bit to get cleared */
537 ret
= readl_relaxed_poll_timeout(prmd
->prm
->base
+ prmd
->pwrstst
,
538 v
, !(v
& PRM_ST_INTRANSITION
), 1,
541 dev_err(prmd
->dev
, "%s: %s timed out\n",
542 prmd
->pd
.name
, __func__
);
544 omap_prm_domain_show_state(prmd
, "on: new state");
549 /* No need to check for holes in the mask for the lowest mode */
550 static int omap_prm_domain_find_lowest(struct omap_prm_domain
*prmd
)
552 return __ffs(prmd
->cap
->usable_modes
);
555 static int omap_prm_domain_power_off(struct generic_pm_domain
*domain
)
557 struct omap_prm_domain
*prmd
;
561 prmd
= genpd_to_prm_domain(domain
);
565 omap_prm_domain_show_state(prmd
, "off: previous state");
567 v
= readl_relaxed(prmd
->prm
->base
+ prmd
->pwrstctrl
);
568 prmd
->pwrstctrl_saved
= v
;
570 v
&= ~PRM_POWERSTATE_MASK
;
571 v
|= omap_prm_domain_find_lowest(prmd
);
573 if (prmd
->cap
->statechange
)
574 v
|= PRM_LOWPOWERSTATECHANGE
;
575 if (prmd
->cap
->logicretstate
)
576 v
&= ~PRM_LOGICRETSTATE
;
578 v
|= PRM_LOGICRETSTATE
;
580 writel_relaxed(v
, prmd
->prm
->base
+ prmd
->pwrstctrl
);
582 /* wait for the transition bit to get cleared */
583 ret
= readl_relaxed_poll_timeout(prmd
->prm
->base
+ prmd
->pwrstst
,
584 v
, !(v
& PRM_ST_INTRANSITION
), 1,
587 dev_warn(prmd
->dev
, "%s: %s timed out\n",
588 __func__
, prmd
->pd
.name
);
590 omap_prm_domain_show_state(prmd
, "off: new state");
596 * Note that ti-sysc already manages the module clocks separately so
597 * no need to manage those. Interconnect instances need clocks managed
600 static int omap_prm_domain_attach_clock(struct device
*dev
,
601 struct omap_prm_domain
*prmd
)
603 struct device_node
*np
= dev
->of_node
;
606 if (!of_device_is_compatible(np
, "simple-pm-bus"))
609 if (!of_property_read_bool(np
, "clocks"))
612 error
= pm_clk_create(dev
);
616 error
= of_pm_clk_add_clks(dev
);
622 prmd
->uses_pm_clk
= 1;
627 static int omap_prm_domain_attach_dev(struct generic_pm_domain
*domain
,
630 struct generic_pm_domain_data
*genpd_data
;
631 struct of_phandle_args pd_args
;
632 struct omap_prm_domain
*prmd
;
633 struct device_node
*np
;
636 prmd
= genpd_to_prm_domain(domain
);
639 ret
= of_parse_phandle_with_args(np
, "power-domains",
640 "#power-domain-cells", 0, &pd_args
);
644 if (pd_args
.args_count
!= 0)
645 dev_warn(dev
, "%s: unusupported #power-domain-cells: %i\n",
646 prmd
->pd
.name
, pd_args
.args_count
);
648 genpd_data
= dev_gpd_data(dev
);
649 genpd_data
->data
= NULL
;
651 ret
= omap_prm_domain_attach_clock(dev
, prmd
);
658 static void omap_prm_domain_detach_dev(struct generic_pm_domain
*domain
,
661 struct generic_pm_domain_data
*genpd_data
;
662 struct omap_prm_domain
*prmd
;
664 prmd
= genpd_to_prm_domain(domain
);
665 if (prmd
->uses_pm_clk
)
667 genpd_data
= dev_gpd_data(dev
);
668 genpd_data
->data
= NULL
;
671 static int omap_prm_domain_init(struct device
*dev
, struct omap_prm
*prm
)
673 struct omap_prm_domain
*prmd
;
674 struct device_node
*np
= dev
->of_node
;
675 const struct omap_prm_data
*data
;
679 if (!of_find_property(dev
->of_node
, "#power-domain-cells", NULL
))
682 of_node_put(dev
->of_node
);
684 prmd
= devm_kzalloc(dev
, sizeof(*prmd
), GFP_KERNEL
);
689 name
= devm_kasprintf(dev
, GFP_KERNEL
, "prm_%s",
694 prmd
->cap
= prmd
->prm
->data
->dmap
;
695 prmd
->pwrstctrl
= prmd
->prm
->data
->pwrstctrl
;
696 prmd
->pwrstst
= prmd
->prm
->data
->pwrstst
;
698 prmd
->pd
.name
= name
;
699 prmd
->pd
.power_on
= omap_prm_domain_power_on
;
700 prmd
->pd
.power_off
= omap_prm_domain_power_off
;
701 prmd
->pd
.attach_dev
= omap_prm_domain_attach_dev
;
702 prmd
->pd
.detach_dev
= omap_prm_domain_detach_dev
;
703 prmd
->pd
.flags
= GENPD_FLAG_PM_CLK
;
705 pm_genpd_init(&prmd
->pd
, NULL
, true);
706 error
= of_genpd_add_provider_simple(np
, &prmd
->pd
);
708 pm_genpd_remove(&prmd
->pd
);
715 static bool _is_valid_reset(struct omap_reset_data
*reset
, unsigned long id
)
717 if (reset
->mask
& BIT(id
))
723 static int omap_reset_get_st_bit(struct omap_reset_data
*reset
,
726 const struct omap_rst_map
*map
= reset
->prm
->data
->rstmap
;
728 while (map
->rst
>= 0) {
738 static int omap_reset_status(struct reset_controller_dev
*rcdev
,
741 struct omap_reset_data
*reset
= to_omap_reset_data(rcdev
);
743 int st_bit
= omap_reset_get_st_bit(reset
, id
);
744 bool has_rstst
= reset
->prm
->data
->rstst
||
745 (reset
->prm
->data
->flags
& OMAP_PRM_HAS_RSTST
);
747 /* Check if we have rstst */
751 /* Check if hw reset line is asserted */
752 v
= readl_relaxed(reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
757 * Check reset status, high value means reset sequence has been
758 * completed successfully so we can return 0 here (reset deasserted)
760 v
= readl_relaxed(reset
->prm
->base
+ reset
->prm
->data
->rstst
);
767 static int omap_reset_assert(struct reset_controller_dev
*rcdev
,
770 struct omap_reset_data
*reset
= to_omap_reset_data(rcdev
);
774 /* assert the reset control line */
775 spin_lock_irqsave(&reset
->lock
, flags
);
776 v
= readl_relaxed(reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
778 writel_relaxed(v
, reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
779 spin_unlock_irqrestore(&reset
->lock
, flags
);
784 static int omap_reset_deassert(struct reset_controller_dev
*rcdev
,
787 struct omap_reset_data
*reset
= to_omap_reset_data(rcdev
);
792 struct ti_prm_platform_data
*pdata
= dev_get_platdata(reset
->dev
);
795 /* Nothing to do if the reset is already deasserted */
796 if (!omap_reset_status(rcdev
, id
))
799 has_rstst
= reset
->prm
->data
->rstst
||
800 (reset
->prm
->data
->flags
& OMAP_PRM_HAS_RSTST
);
803 st_bit
= omap_reset_get_st_bit(reset
, id
);
805 /* Clear the reset status by writing 1 to the status bit */
807 writel_relaxed(v
, reset
->prm
->base
+ reset
->prm
->data
->rstst
);
811 pdata
->clkdm_deny_idle(reset
->clkdm
);
813 /* de-assert the reset control line */
814 spin_lock_irqsave(&reset
->lock
, flags
);
815 v
= readl_relaxed(reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
817 writel_relaxed(v
, reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
818 spin_unlock_irqrestore(&reset
->lock
, flags
);
823 /* wait for the status to be set */
824 ret
= readl_relaxed_poll_timeout_atomic(reset
->prm
->base
+
825 reset
->prm
->data
->rstst
,
826 v
, v
& BIT(st_bit
), 1,
827 OMAP_RESET_MAX_WAIT
);
829 pr_err("%s: timedout waiting for %s:%lu\n", __func__
,
830 reset
->prm
->data
->name
, id
);
834 pdata
->clkdm_allow_idle(reset
->clkdm
);
839 static const struct reset_control_ops omap_reset_ops
= {
840 .assert = omap_reset_assert
,
841 .deassert
= omap_reset_deassert
,
842 .status
= omap_reset_status
,
845 static int omap_prm_reset_xlate(struct reset_controller_dev
*rcdev
,
846 const struct of_phandle_args
*reset_spec
)
848 struct omap_reset_data
*reset
= to_omap_reset_data(rcdev
);
850 if (!_is_valid_reset(reset
, reset_spec
->args
[0]))
853 return reset_spec
->args
[0];
856 static int omap_prm_reset_init(struct platform_device
*pdev
,
857 struct omap_prm
*prm
)
859 struct omap_reset_data
*reset
;
860 const struct omap_rst_map
*map
;
861 struct ti_prm_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
865 * Check if we have controllable resets. If either rstctrl is non-zero
866 * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
869 if (!prm
->data
->rstctrl
&& !(prm
->data
->flags
& OMAP_PRM_HAS_RSTCTRL
))
872 /* Check if we have the pdata callbacks in place */
873 if (!pdata
|| !pdata
->clkdm_lookup
|| !pdata
->clkdm_deny_idle
||
874 !pdata
->clkdm_allow_idle
)
877 map
= prm
->data
->rstmap
;
881 reset
= devm_kzalloc(&pdev
->dev
, sizeof(*reset
), GFP_KERNEL
);
885 reset
->rcdev
.owner
= THIS_MODULE
;
886 reset
->rcdev
.ops
= &omap_reset_ops
;
887 reset
->rcdev
.of_node
= pdev
->dev
.of_node
;
888 reset
->rcdev
.nr_resets
= OMAP_MAX_RESETS
;
889 reset
->rcdev
.of_xlate
= omap_prm_reset_xlate
;
890 reset
->rcdev
.of_reset_n_cells
= 1;
891 reset
->dev
= &pdev
->dev
;
892 spin_lock_init(&reset
->lock
);
896 sprintf(buf
, "%s_clkdm", prm
->data
->clkdm_name
? prm
->data
->clkdm_name
:
899 if (!(prm
->data
->flags
& OMAP_PRM_HAS_NO_CLKDM
)) {
900 reset
->clkdm
= pdata
->clkdm_lookup(buf
);
905 while (map
->rst
>= 0) {
906 reset
->mask
|= BIT(map
->rst
);
910 return devm_reset_controller_register(&pdev
->dev
, &reset
->rcdev
);
913 static int omap_prm_probe(struct platform_device
*pdev
)
915 struct resource
*res
;
916 const struct omap_prm_data
*data
;
917 struct omap_prm
*prm
;
918 const struct of_device_id
*match
;
921 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
925 match
= of_match_device(omap_prm_id_table
, &pdev
->dev
);
929 prm
= devm_kzalloc(&pdev
->dev
, sizeof(*prm
), GFP_KERNEL
);
935 while (data
->base
!= res
->start
) {
943 prm
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
944 if (IS_ERR(prm
->base
))
945 return PTR_ERR(prm
->base
);
947 ret
= omap_prm_domain_init(&pdev
->dev
, prm
);
951 ret
= omap_prm_reset_init(pdev
, prm
);
958 of_genpd_del_provider(pdev
->dev
.of_node
);
959 pm_genpd_remove(&prm
->prmd
->pd
);
964 static struct platform_driver omap_prm_driver
= {
965 .probe
= omap_prm_probe
,
967 .name
= KBUILD_MODNAME
,
968 .of_match_table
= omap_prm_id_table
,
971 builtin_platform_driver(omap_prm_driver
);