linux/drivers/soc/ti/omap_prm.c
<<
>>
Prefs
   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        if (!has_rstst)
 829                goto exit;
 830
 831        /* wait for the status to be set */
 832        ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
 833                                                 reset->prm->data->rstst,
 834                                                 v, v & BIT(st_bit), 1,
 835                                                 OMAP_RESET_MAX_WAIT);
 836        if (ret)
 837                pr_err("%s: timedout waiting for %s:%lu\n", __func__,
 838                       reset->prm->data->name, id);
 839
 840exit:
 841        if (reset->clkdm) {
 842                /* At least dra7 iva needs a delay before clkdm idle */
 843                if (has_rstst)
 844                        udelay(1);
 845                pdata->clkdm_allow_idle(reset->clkdm);
 846        }
 847
 848        return ret;
 849}
 850
 851static const struct reset_control_ops omap_reset_ops = {
 852        .assert         = omap_reset_assert,
 853        .deassert       = omap_reset_deassert,
 854        .status         = omap_reset_status,
 855};
 856
 857static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev,
 858                                const struct of_phandle_args *reset_spec)
 859{
 860        struct omap_reset_data *reset = to_omap_reset_data(rcdev);
 861
 862        if (!_is_valid_reset(reset, reset_spec->args[0]))
 863                return -EINVAL;
 864
 865        return reset_spec->args[0];
 866}
 867
 868static int omap_prm_reset_init(struct platform_device *pdev,
 869                               struct omap_prm *prm)
 870{
 871        struct omap_reset_data *reset;
 872        const struct omap_rst_map *map;
 873        struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev);
 874        char buf[32];
 875        u32 v;
 876
 877        /*
 878         * Check if we have controllable resets. If either rstctrl is non-zero
 879         * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
 880         * for the domain.
 881         */
 882        if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL))
 883                return 0;
 884
 885        /* Check if we have the pdata callbacks in place */
 886        if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle ||
 887            !pdata->clkdm_allow_idle)
 888                return -EINVAL;
 889
 890        map = prm->data->rstmap;
 891        if (!map)
 892                return -EINVAL;
 893
 894        reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
 895        if (!reset)
 896                return -ENOMEM;
 897
 898        reset->rcdev.owner = THIS_MODULE;
 899        reset->rcdev.ops = &omap_reset_ops;
 900        reset->rcdev.of_node = pdev->dev.of_node;
 901        reset->rcdev.nr_resets = OMAP_MAX_RESETS;
 902        reset->rcdev.of_xlate = omap_prm_reset_xlate;
 903        reset->rcdev.of_reset_n_cells = 1;
 904        reset->dev = &pdev->dev;
 905        spin_lock_init(&reset->lock);
 906
 907        reset->prm = prm;
 908
 909        sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name :
 910                prm->data->name);
 911
 912        if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) {
 913                reset->clkdm = pdata->clkdm_lookup(buf);
 914                if (!reset->clkdm)
 915                        return -EINVAL;
 916        }
 917
 918        while (map->rst >= 0) {
 919                reset->mask |= BIT(map->rst);
 920                map++;
 921        }
 922
 923        /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */
 924        if (prm->data->rstmap == rst_map_012) {
 925                v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
 926                if ((v & reset->mask) != reset->mask) {
 927                        dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v);
 928                        writel_relaxed(reset->mask, reset->prm->base +
 929                                       reset->prm->data->rstctrl);
 930                }
 931        }
 932
 933        return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
 934}
 935
 936static int omap_prm_probe(struct platform_device *pdev)
 937{
 938        struct resource *res;
 939        const struct omap_prm_data *data;
 940        struct omap_prm *prm;
 941        const struct of_device_id *match;
 942        int ret;
 943
 944        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 945        if (!res)
 946                return -ENODEV;
 947
 948        match = of_match_device(omap_prm_id_table, &pdev->dev);
 949        if (!match)
 950                return -ENOTSUPP;
 951
 952        prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL);
 953        if (!prm)
 954                return -ENOMEM;
 955
 956        data = match->data;
 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);
 995