Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.12-rc7 986 lines 25 kB view raw
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 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 }, 179 { 180 .name = "ivahd", .base = 0x4a306f00, 181 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 182 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 183 }, 184 { 185 .name = "cam", .base = 0x4a307000, 186 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 187 }, 188 { 189 .name = "dss", .base = 0x4a307100, 190 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact 191 }, 192 { 193 .name = "gfx", .base = 0x4a307200, 194 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 195 }, 196 { 197 .name = "l3init", .base = 0x4a307300, 198 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton 199 }, 200 { 201 .name = "l4per", .base = 0x4a307400, 202 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton 203 }, 204 { 205 .name = "cefuse", .base = 0x4a307600, 206 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 207 }, 208 { 209 .name = "wkup", .base = 0x4a307700, 210 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon 211 }, 212 { 213 .name = "emu", .base = 0x4a307900, 214 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 215 }, 216 { 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 220 }, 221 { }, 222}; 223 224static const struct omap_prm_data omap5_prm_data[] = { 225 { 226 .name = "mpu", .base = 0x4ae06300, 227 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, 228 }, 229 { 230 .name = "dsp", .base = 0x4ae06400, 231 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 232 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 233 }, 234 { 235 .name = "abe", .base = 0x4ae06500, 236 .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff, 237 }, 238 { 239 .name = "coreaon", .base = 0x4ae06600, 240 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon 241 }, 242 { 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 247 }, 248 { 249 .name = "iva", .base = 0x4ae07200, 250 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 251 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 252 }, 253 { 254 .name = "cam", .base = 0x4ae07300, 255 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 256 }, 257 { 258 .name = "dss", .base = 0x4ae07400, 259 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact 260 }, 261 { 262 .name = "gpu", .base = 0x4ae07500, 263 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 264 }, 265 { 266 .name = "l3init", .base = 0x4ae07600, 267 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton 268 }, 269 { 270 .name = "custefuse", .base = 0x4ae07700, 271 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 272 }, 273 { 274 .name = "wkupaon", .base = 0x4ae07800, 275 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon 276 }, 277 { 278 .name = "emu", .base = 0x4ae07a00, 279 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 280 }, 281 { 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 285 }, 286 { }, 287}; 288 289static const struct omap_prm_data dra7_prm_data[] = { 290 { 291 .name = "mpu", .base = 0x4ae06300, 292 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, 293 }, 294 { 295 .name = "dsp1", .base = 0x4ae06400, 296 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 297 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01, 298 }, 299 { 300 .name = "ipu", .base = 0x4ae06500, 301 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 302 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012, 303 .clkdm_name = "ipu1" 304 }, 305 { 306 .name = "coreaon", .base = 0x4ae06628, 307 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 308 }, 309 { 310 .name = "core", .base = 0x4ae06700, 311 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 312 .rstctrl = 0x210, .rstst = 0x214, .rstmap = rst_map_012, 313 .clkdm_name = "ipu2" 314 }, 315 { 316 .name = "iva", .base = 0x4ae06f00, 317 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 318 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012, 319 }, 320 { 321 .name = "cam", .base = 0x4ae07000, 322 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 323 }, 324 { 325 .name = "dss", .base = 0x4ae07100, 326 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 327 }, 328 { 329 .name = "gpu", .base = 0x4ae07200, 330 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 331 }, 332 { 333 .name = "l3init", .base = 0x4ae07300, 334 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 335 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01, 336 .clkdm_name = "pcie" 337 }, 338 { 339 .name = "l4per", .base = 0x4ae07400, 340 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 341 }, 342 { 343 .name = "custefuse", .base = 0x4ae07600, 344 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 345 }, 346 { 347 .name = "wkupaon", .base = 0x4ae07724, 348 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 349 }, 350 { 351 .name = "emu", .base = 0x4ae07900, 352 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 353 }, 354 { 355 .name = "dsp2", .base = 0x4ae07b00, 356 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 357 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 358 }, 359 { 360 .name = "eve1", .base = 0x4ae07b40, 361 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 362 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 363 }, 364 { 365 .name = "eve2", .base = 0x4ae07b80, 366 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 367 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 368 }, 369 { 370 .name = "eve3", .base = 0x4ae07bc0, 371 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 372 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 373 }, 374 { 375 .name = "eve4", .base = 0x4ae07c00, 376 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 377 .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 378 }, 379 { 380 .name = "rtc", .base = 0x4ae07c60, 381 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 382 }, 383 { 384 .name = "vpe", .base = 0x4ae07c80, 385 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 386 }, 387 { }, 388}; 389 390static const struct omap_rst_map am3_per_rst_map[] = { 391 { .rst = 1 }, 392 { .rst = -1 }, 393}; 394 395static const struct omap_rst_map am3_wkup_rst_map[] = { 396 { .rst = 3, .st = 5 }, 397 { .rst = -1 }, 398}; 399 400static const struct omap_prm_data am3_prm_data[] = { 401 { 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" 406 }, 407 { 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 412 }, 413 { 414 .name = "mpu", .base = 0x44e00e00, 415 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 416 }, 417 { 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 421 }, 422 { 423 .name = "rtc", .base = 0x44e01000, 424 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 425 }, 426 { 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", 430 }, 431 { 432 .name = "cefuse", .base = 0x44e01200, 433 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 434 }, 435 { }, 436}; 437 438static const struct omap_rst_map am4_per_rst_map[] = { 439 { .rst = 1, .st = 0 }, 440 { .rst = -1 }, 441}; 442 443static const struct omap_rst_map am4_device_rst_map[] = { 444 { .rst = 0, .st = 1 }, 445 { .rst = 1, .st = 0 }, 446 { .rst = -1 }, 447}; 448 449static const struct omap_prm_data am4_prm_data[] = { 450 { 451 .name = "mpu", .base = 0x44df0300, 452 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 453 }, 454 { 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", 458 }, 459 { 460 .name = "rtc", .base = 0x44df0500, 461 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 462 }, 463 { 464 .name = "tamper", .base = 0x44df0600, 465 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 466 }, 467 { 468 .name = "cefuse", .base = 0x44df0700, 469 .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 470 }, 471 { 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" 476 }, 477 { 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 482 }, 483 { 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 487 }, 488 { }, 489}; 490 491static 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 }, 497 { }, 498}; 499 500#ifdef DEBUG 501static void omap_prm_domain_show_state(struct omap_prm_domain *prmd, 502 const char *desc) 503{ 504 dev_dbg(prmd->dev, "%s %s: %08x/%08x\n", 505 prmd->pd.name, desc, 506 readl_relaxed(prmd->prm->base + prmd->pwrstctrl), 507 readl_relaxed(prmd->prm->base + prmd->pwrstst)); 508} 509#else 510static inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd, 511 const char *desc) 512{ 513} 514#endif 515 516static int omap_prm_domain_power_on(struct generic_pm_domain *domain) 517{ 518 struct omap_prm_domain *prmd; 519 int ret; 520 u32 v; 521 522 prmd = genpd_to_prm_domain(domain); 523 if (!prmd->cap) 524 return 0; 525 526 omap_prm_domain_show_state(prmd, "on: previous state"); 527 528 if (prmd->pwrstctrl_saved) 529 v = prmd->pwrstctrl_saved; 530 else 531 v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); 532 533 writel_relaxed(v | OMAP_PRMD_ON_ACTIVE, 534 prmd->prm->base + prmd->pwrstctrl); 535 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, 539 PRM_STATE_MAX_WAIT); 540 if (ret) 541 dev_err(prmd->dev, "%s: %s timed out\n", 542 prmd->pd.name, __func__); 543 544 omap_prm_domain_show_state(prmd, "on: new state"); 545 546 return ret; 547} 548 549/* No need to check for holes in the mask for the lowest mode */ 550static int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd) 551{ 552 return __ffs(prmd->cap->usable_modes); 553} 554 555static int omap_prm_domain_power_off(struct generic_pm_domain *domain) 556{ 557 struct omap_prm_domain *prmd; 558 int ret; 559 u32 v; 560 561 prmd = genpd_to_prm_domain(domain); 562 if (!prmd->cap) 563 return 0; 564 565 omap_prm_domain_show_state(prmd, "off: previous state"); 566 567 v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); 568 prmd->pwrstctrl_saved = v; 569 570 v &= ~PRM_POWERSTATE_MASK; 571 v |= omap_prm_domain_find_lowest(prmd); 572 573 if (prmd->cap->statechange) 574 v |= PRM_LOWPOWERSTATECHANGE; 575 if (prmd->cap->logicretstate) 576 v &= ~PRM_LOGICRETSTATE; 577 else 578 v |= PRM_LOGICRETSTATE; 579 580 writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl); 581 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, 585 PRM_STATE_MAX_WAIT); 586 if (ret) 587 dev_warn(prmd->dev, "%s: %s timed out\n", 588 __func__, prmd->pd.name); 589 590 omap_prm_domain_show_state(prmd, "off: new state"); 591 592 return 0; 593} 594 595/* 596 * Note that ti-sysc already manages the module clocks separately so 597 * no need to manage those. Interconnect instances need clocks managed 598 * for simple-pm-bus. 599 */ 600static int omap_prm_domain_attach_clock(struct device *dev, 601 struct omap_prm_domain *prmd) 602{ 603 struct device_node *np = dev->of_node; 604 int error; 605 606 if (!of_device_is_compatible(np, "simple-pm-bus")) 607 return 0; 608 609 if (!of_property_read_bool(np, "clocks")) 610 return 0; 611 612 error = pm_clk_create(dev); 613 if (error) 614 return error; 615 616 error = of_pm_clk_add_clks(dev); 617 if (error < 0) { 618 pm_clk_destroy(dev); 619 return error; 620 } 621 622 prmd->uses_pm_clk = 1; 623 624 return 0; 625} 626 627static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, 628 struct device *dev) 629{ 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; 634 int ret; 635 636 prmd = genpd_to_prm_domain(domain); 637 np = dev->of_node; 638 639 ret = of_parse_phandle_with_args(np, "power-domains", 640 "#power-domain-cells", 0, &pd_args); 641 if (ret < 0) 642 return ret; 643 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); 647 648 genpd_data = dev_gpd_data(dev); 649 genpd_data->data = NULL; 650 651 ret = omap_prm_domain_attach_clock(dev, prmd); 652 if (ret) 653 return ret; 654 655 return 0; 656} 657 658static void omap_prm_domain_detach_dev(struct generic_pm_domain *domain, 659 struct device *dev) 660{ 661 struct generic_pm_domain_data *genpd_data; 662 struct omap_prm_domain *prmd; 663 664 prmd = genpd_to_prm_domain(domain); 665 if (prmd->uses_pm_clk) 666 pm_clk_destroy(dev); 667 genpd_data = dev_gpd_data(dev); 668 genpd_data->data = NULL; 669} 670 671static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm) 672{ 673 struct omap_prm_domain *prmd; 674 struct device_node *np = dev->of_node; 675 const struct omap_prm_data *data; 676 const char *name; 677 int error; 678 679 if (!of_find_property(dev->of_node, "#power-domain-cells", NULL)) 680 return 0; 681 682 of_node_put(dev->of_node); 683 684 prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL); 685 if (!prmd) 686 return -ENOMEM; 687 688 data = prm->data; 689 name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s", 690 data->name); 691 692 prmd->dev = dev; 693 prmd->prm = prm; 694 prmd->cap = prmd->prm->data->dmap; 695 prmd->pwrstctrl = prmd->prm->data->pwrstctrl; 696 prmd->pwrstst = prmd->prm->data->pwrstst; 697 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; 704 705 pm_genpd_init(&prmd->pd, NULL, true); 706 error = of_genpd_add_provider_simple(np, &prmd->pd); 707 if (error) 708 pm_genpd_remove(&prmd->pd); 709 else 710 prm->prmd = prmd; 711 712 return error; 713} 714 715static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id) 716{ 717 if (reset->mask & BIT(id)) 718 return true; 719 720 return false; 721} 722 723static int omap_reset_get_st_bit(struct omap_reset_data *reset, 724 unsigned long id) 725{ 726 const struct omap_rst_map *map = reset->prm->data->rstmap; 727 728 while (map->rst >= 0) { 729 if (map->rst == id) 730 return map->st; 731 732 map++; 733 } 734 735 return id; 736} 737 738static int omap_reset_status(struct reset_controller_dev *rcdev, 739 unsigned long id) 740{ 741 struct omap_reset_data *reset = to_omap_reset_data(rcdev); 742 u32 v; 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); 746 747 /* Check if we have rstst */ 748 if (!has_rstst) 749 return -ENOTSUPP; 750 751 /* Check if hw reset line is asserted */ 752 v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 753 if (v & BIT(id)) 754 return 1; 755 756 /* 757 * Check reset status, high value means reset sequence has been 758 * completed successfully so we can return 0 here (reset deasserted) 759 */ 760 v = readl_relaxed(reset->prm->base + reset->prm->data->rstst); 761 v >>= st_bit; 762 v &= 1; 763 764 return !v; 765} 766 767static int omap_reset_assert(struct reset_controller_dev *rcdev, 768 unsigned long id) 769{ 770 struct omap_reset_data *reset = to_omap_reset_data(rcdev); 771 u32 v; 772 unsigned long flags; 773 774 /* assert the reset control line */ 775 spin_lock_irqsave(&reset->lock, flags); 776 v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 777 v |= 1 << id; 778 writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl); 779 spin_unlock_irqrestore(&reset->lock, flags); 780 781 return 0; 782} 783 784static int omap_reset_deassert(struct reset_controller_dev *rcdev, 785 unsigned long id) 786{ 787 struct omap_reset_data *reset = to_omap_reset_data(rcdev); 788 u32 v; 789 int st_bit; 790 bool has_rstst; 791 unsigned long flags; 792 struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev); 793 int ret = 0; 794 795 /* Nothing to do if the reset is already deasserted */ 796 if (!omap_reset_status(rcdev, id)) 797 return 0; 798 799 has_rstst = reset->prm->data->rstst || 800 (reset->prm->data->flags & OMAP_PRM_HAS_RSTST); 801 802 if (has_rstst) { 803 st_bit = omap_reset_get_st_bit(reset, id); 804 805 /* Clear the reset status by writing 1 to the status bit */ 806 v = 1 << st_bit; 807 writel_relaxed(v, reset->prm->base + reset->prm->data->rstst); 808 } 809 810 if (reset->clkdm) 811 pdata->clkdm_deny_idle(reset->clkdm); 812 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); 816 v &= ~(1 << id); 817 writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl); 818 spin_unlock_irqrestore(&reset->lock, flags); 819 820 if (!has_rstst) 821 goto exit; 822 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); 828 if (ret) 829 pr_err("%s: timedout waiting for %s:%lu\n", __func__, 830 reset->prm->data->name, id); 831 832exit: 833 if (reset->clkdm) { 834 /* At least dra7 iva needs a delay before clkdm idle */ 835 if (has_rstst) 836 udelay(1); 837 pdata->clkdm_allow_idle(reset->clkdm); 838 } 839 840 return ret; 841} 842 843static const struct reset_control_ops omap_reset_ops = { 844 .assert = omap_reset_assert, 845 .deassert = omap_reset_deassert, 846 .status = omap_reset_status, 847}; 848 849static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev, 850 const struct of_phandle_args *reset_spec) 851{ 852 struct omap_reset_data *reset = to_omap_reset_data(rcdev); 853 854 if (!_is_valid_reset(reset, reset_spec->args[0])) 855 return -EINVAL; 856 857 return reset_spec->args[0]; 858} 859 860static int omap_prm_reset_init(struct platform_device *pdev, 861 struct omap_prm *prm) 862{ 863 struct omap_reset_data *reset; 864 const struct omap_rst_map *map; 865 struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev); 866 char buf[32]; 867 u32 v; 868 869 /* 870 * Check if we have controllable resets. If either rstctrl is non-zero 871 * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register 872 * for the domain. 873 */ 874 if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL)) 875 return 0; 876 877 /* Check if we have the pdata callbacks in place */ 878 if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle || 879 !pdata->clkdm_allow_idle) 880 return -EINVAL; 881 882 map = prm->data->rstmap; 883 if (!map) 884 return -EINVAL; 885 886 reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); 887 if (!reset) 888 return -ENOMEM; 889 890 reset->rcdev.owner = THIS_MODULE; 891 reset->rcdev.ops = &omap_reset_ops; 892 reset->rcdev.of_node = pdev->dev.of_node; 893 reset->rcdev.nr_resets = OMAP_MAX_RESETS; 894 reset->rcdev.of_xlate = omap_prm_reset_xlate; 895 reset->rcdev.of_reset_n_cells = 1; 896 reset->dev = &pdev->dev; 897 spin_lock_init(&reset->lock); 898 899 reset->prm = prm; 900 901 sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name : 902 prm->data->name); 903 904 if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) { 905 reset->clkdm = pdata->clkdm_lookup(buf); 906 if (!reset->clkdm) 907 return -EINVAL; 908 } 909 910 while (map->rst >= 0) { 911 reset->mask |= BIT(map->rst); 912 map++; 913 } 914 915 /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */ 916 if (prm->data->rstmap == rst_map_012) { 917 v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 918 if ((v & reset->mask) != reset->mask) { 919 dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v); 920 writel_relaxed(reset->mask, reset->prm->base + 921 reset->prm->data->rstctrl); 922 } 923 } 924 925 return devm_reset_controller_register(&pdev->dev, &reset->rcdev); 926} 927 928static int omap_prm_probe(struct platform_device *pdev) 929{ 930 struct resource *res; 931 const struct omap_prm_data *data; 932 struct omap_prm *prm; 933 const struct of_device_id *match; 934 int ret; 935 936 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 937 if (!res) 938 return -ENODEV; 939 940 match = of_match_device(omap_prm_id_table, &pdev->dev); 941 if (!match) 942 return -ENOTSUPP; 943 944 prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL); 945 if (!prm) 946 return -ENOMEM; 947 948 data = match->data; 949 950 while (data->base != res->start) { 951 if (!data->base) 952 return -EINVAL; 953 data++; 954 } 955 956 prm->data = data; 957 958 prm->base = devm_ioremap_resource(&pdev->dev, res); 959 if (IS_ERR(prm->base)) 960 return PTR_ERR(prm->base); 961 962 ret = omap_prm_domain_init(&pdev->dev, prm); 963 if (ret) 964 return ret; 965 966 ret = omap_prm_reset_init(pdev, prm); 967 if (ret) 968 goto err_domain; 969 970 return 0; 971 972err_domain: 973 of_genpd_del_provider(pdev->dev.of_node); 974 pm_genpd_remove(&prm->prmd->pd); 975 976 return ret; 977} 978 979static struct platform_driver omap_prm_driver = { 980 .probe = omap_prm_probe, 981 .driver = { 982 .name = KBUILD_MODNAME, 983 .of_match_table = omap_prm_id_table, 984 }, 985}; 986builtin_platform_driver(omap_prm_driver);