omap_prm.c (25791B)
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);