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
  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_012,
 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                pdata->clkdm_allow_idle(reset->clkdm);
 835
 836        return ret;
 837}
 838
 839static const struct reset_control_ops omap_reset_ops = {
 840        .assert         = omap_reset_assert,
 841        .deassert       = omap_reset_deassert,
 842        .status         = omap_reset_status,
 843};
 844
 845static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev,
 846                                const struct of_phandle_args *reset_spec)
 847{
 848        struct omap_reset_data *reset = to_omap_reset_data(rcdev);
 849
 850        if (!_is_valid_reset(reset, reset_spec->args[0]))
 851                return -EINVAL;
 852
 853        return reset_spec->args[0];
 854}
 855
 856static int omap_prm_reset_init(struct platform_device *pdev,
 857                               struct omap_prm *prm)
 858{
 859        struct omap_reset_data *reset;
 860        const struct omap_rst_map *map;
 861        struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev);
 862        char buf[32];
 863        u32 v;
 864
 865        /*
 866         * Check if we have controllable resets. If either rstctrl is non-zero
 867         * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
 868         * for the domain.
 869         */
 870        if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL))
 871                return 0;
 872
 873        /* Check if we have the pdata callbacks in place */
 874        if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle ||
 875            !pdata->clkdm_allow_idle)
 876                return -EINVAL;
 877
 878        map = prm->data->rstmap;
 879        if (!map)
 880                return -EINVAL;
 881
 882        reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
 883        if (!reset)
 884                return -ENOMEM;
 885
 886        reset->rcdev.owner = THIS_MODULE;
 887        reset->rcdev.ops = &omap_reset_ops;
 888        reset->rcdev.of_node = pdev->dev.of_node;
 889        reset->rcdev.nr_resets = OMAP_MAX_RESETS;
 890        reset->rcdev.of_xlate = omap_prm_reset_xlate;
 891        reset->rcdev.of_reset_n_cells = 1;
 892        reset->dev = &pdev->dev;
 893        spin_lock_init(&reset->lock);
 894
 895        reset->prm = prm;
 896
 897        sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name :
 898                prm->data->name);
 899
 900        if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) {
 901                reset->clkdm = pdata->clkdm_lookup(buf);
 902                if (!reset->clkdm)
 903                        return -EINVAL;
 904        }
 905
 906        while (map->rst >= 0) {
 907                reset->mask |= BIT(map->rst);
 908                map++;
 909        }
 910
 911        /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */
 912        if (prm->data->rstmap == rst_map_012) {
 913                v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
 914                if ((v & reset->mask) != reset->mask) {
 915                        dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v);
 916                        writel_relaxed(reset->mask, reset->prm->base +
 917                                       reset->prm->data->rstctrl);
 918                }
 919        }
 920
 921        return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
 922}
 923
 924static int omap_prm_probe(struct platform_device *pdev)
 925{
 926        struct resource *res;
 927        const struct omap_prm_data *data;
 928        struct omap_prm *prm;
 929        const struct of_device_id *match;
 930        int ret;
 931
 932        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 933        if (!res)
 934                return -ENODEV;
 935
 936        match = of_match_device(omap_prm_id_table, &pdev->dev);
 937        if (!match)
 938                return -ENOTSUPP;
 939
 940        prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL);
 941        if (!prm)
 942                return -ENOMEM;
 943
 944        data = match->data;
 945
 946        while (data->base != res->start) {
 947                if (!data->base)
 948                        return -EINVAL;
 949                data++;
 950        }
 951
 952        prm->data = data;
 953
 954        prm->base = devm_ioremap_resource(&pdev->dev, res);
 955        if (IS_ERR(prm->base))
 956                return PTR_ERR(prm->base);
 957
 958        ret = omap_prm_domain_init(&pdev->dev, prm);
 959        if (ret)
 960                return ret;
 961
 962        ret = omap_prm_reset_init(pdev, prm);
 963        if (ret)
 964                goto err_domain;
 965
 966        return 0;
 967
 968err_domain:
 969        of_genpd_del_provider(pdev->dev.of_node);
 970        pm_genpd_remove(&prm->prmd->pd);
 971
 972        return ret;
 973}
 974
 975static struct platform_driver omap_prm_driver = {
 976        .probe = omap_prm_probe,
 977        .driver = {
 978                .name           = KBUILD_MODNAME,
 979                .of_match_table = omap_prm_id_table,
 980        },
 981};
 982builtin_platform_driver(omap_prm_driver);
 983