1e2ad626fSUlf Hansson // SPDX-License-Identifier: GPL-2.0 2e2ad626fSUlf Hansson /* 3e2ad626fSUlf Hansson * OMAP2+ PRM driver 4e2ad626fSUlf Hansson * 5e2ad626fSUlf Hansson * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 6e2ad626fSUlf Hansson * Tero Kristo <t-kristo@ti.com> 7e2ad626fSUlf Hansson */ 8e2ad626fSUlf Hansson 9e2ad626fSUlf Hansson #include <linux/kernel.h> 10e2ad626fSUlf Hansson #include <linux/clk.h> 11e2ad626fSUlf Hansson #include <linux/device.h> 12e2ad626fSUlf Hansson #include <linux/io.h> 13e2ad626fSUlf Hansson #include <linux/iopoll.h> 14e2ad626fSUlf Hansson #include <linux/module.h> 15e2ad626fSUlf Hansson #include <linux/of.h> 16e2ad626fSUlf Hansson #include <linux/platform_device.h> 17e2ad626fSUlf Hansson #include <linux/pm_clock.h> 18e2ad626fSUlf Hansson #include <linux/pm_domain.h> 19e2ad626fSUlf Hansson #include <linux/reset-controller.h> 20e2ad626fSUlf Hansson #include <linux/delay.h> 21e2ad626fSUlf Hansson 22e2ad626fSUlf Hansson #include <linux/platform_data/ti-prm.h> 23e2ad626fSUlf Hansson 24e2ad626fSUlf Hansson enum omap_prm_domain_mode { 25e2ad626fSUlf Hansson OMAP_PRMD_OFF, 26e2ad626fSUlf Hansson OMAP_PRMD_RETENTION, 27e2ad626fSUlf Hansson OMAP_PRMD_ON_INACTIVE, 28e2ad626fSUlf Hansson OMAP_PRMD_ON_ACTIVE, 29e2ad626fSUlf Hansson }; 30e2ad626fSUlf Hansson 31e2ad626fSUlf Hansson struct omap_prm_domain_map { 32e2ad626fSUlf Hansson unsigned int usable_modes; /* Mask of hardware supported modes */ 33e2ad626fSUlf Hansson unsigned long statechange:1; /* Optional low-power state change */ 34e2ad626fSUlf Hansson unsigned long logicretstate:1; /* Optional logic off mode */ 35e2ad626fSUlf Hansson }; 36e2ad626fSUlf Hansson 37e2ad626fSUlf Hansson struct omap_prm_domain { 38e2ad626fSUlf Hansson struct device *dev; 39e2ad626fSUlf Hansson struct omap_prm *prm; 40e2ad626fSUlf Hansson struct generic_pm_domain pd; 41e2ad626fSUlf Hansson u16 pwrstctrl; 42e2ad626fSUlf Hansson u16 pwrstst; 43e2ad626fSUlf Hansson const struct omap_prm_domain_map *cap; 44e2ad626fSUlf Hansson u32 pwrstctrl_saved; 45e2ad626fSUlf Hansson unsigned int uses_pm_clk:1; 46e2ad626fSUlf Hansson }; 47e2ad626fSUlf Hansson 48e2ad626fSUlf Hansson struct omap_rst_map { 49e2ad626fSUlf Hansson s8 rst; 50e2ad626fSUlf Hansson s8 st; 51e2ad626fSUlf Hansson }; 52e2ad626fSUlf Hansson 53e2ad626fSUlf Hansson struct omap_prm_data { 54e2ad626fSUlf Hansson u32 base; 55e2ad626fSUlf Hansson const char *name; 56e2ad626fSUlf Hansson const char *clkdm_name; 57e2ad626fSUlf Hansson u16 pwrstctrl; 58e2ad626fSUlf Hansson u16 pwrstst; 59e2ad626fSUlf Hansson const struct omap_prm_domain_map *dmap; 60e2ad626fSUlf Hansson u16 rstctrl; 61e2ad626fSUlf Hansson u16 rstst; 62e2ad626fSUlf Hansson const struct omap_rst_map *rstmap; 63e2ad626fSUlf Hansson u8 flags; 64e2ad626fSUlf Hansson }; 65e2ad626fSUlf Hansson 66e2ad626fSUlf Hansson struct omap_prm { 67e2ad626fSUlf Hansson const struct omap_prm_data *data; 68e2ad626fSUlf Hansson void __iomem *base; 69e2ad626fSUlf Hansson struct omap_prm_domain *prmd; 70e2ad626fSUlf Hansson }; 71e2ad626fSUlf Hansson 72e2ad626fSUlf Hansson struct omap_reset_data { 73e2ad626fSUlf Hansson struct reset_controller_dev rcdev; 74e2ad626fSUlf Hansson struct omap_prm *prm; 75e2ad626fSUlf Hansson u32 mask; 76e2ad626fSUlf Hansson spinlock_t lock; 77e2ad626fSUlf Hansson struct clockdomain *clkdm; 78e2ad626fSUlf Hansson struct device *dev; 79e2ad626fSUlf Hansson }; 80e2ad626fSUlf Hansson 81e2ad626fSUlf Hansson #define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd) 82e2ad626fSUlf Hansson #define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev) 83e2ad626fSUlf Hansson 84e2ad626fSUlf Hansson #define OMAP_MAX_RESETS 8 85e2ad626fSUlf Hansson #define OMAP_RESET_MAX_WAIT 10000 86e2ad626fSUlf Hansson 87e2ad626fSUlf Hansson #define OMAP_PRM_HAS_RSTCTRL BIT(0) 88e2ad626fSUlf Hansson #define OMAP_PRM_HAS_RSTST BIT(1) 89e2ad626fSUlf Hansson #define OMAP_PRM_HAS_NO_CLKDM BIT(2) 90e2ad626fSUlf Hansson #define OMAP_PRM_RET_WHEN_IDLE BIT(3) 91e2ad626fSUlf Hansson 92e2ad626fSUlf Hansson #define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST) 93e2ad626fSUlf Hansson 94e2ad626fSUlf Hansson #define PRM_STATE_MAX_WAIT 10000 95e2ad626fSUlf Hansson #define PRM_LOGICRETSTATE BIT(2) 96e2ad626fSUlf Hansson #define PRM_LOWPOWERSTATECHANGE BIT(4) 97e2ad626fSUlf Hansson #define PRM_POWERSTATE_MASK OMAP_PRMD_ON_ACTIVE 98e2ad626fSUlf Hansson 99e2ad626fSUlf Hansson #define PRM_ST_INTRANSITION BIT(20) 100e2ad626fSUlf Hansson 101e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_all = { 102e2ad626fSUlf Hansson .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) | 103e2ad626fSUlf Hansson BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF), 104e2ad626fSUlf Hansson .statechange = 1, 105e2ad626fSUlf Hansson .logicretstate = 1, 106e2ad626fSUlf Hansson }; 107e2ad626fSUlf Hansson 108e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_noinact = { 109e2ad626fSUlf Hansson .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) | 110e2ad626fSUlf Hansson BIT(OMAP_PRMD_OFF), 111e2ad626fSUlf Hansson .statechange = 1, 112e2ad626fSUlf Hansson .logicretstate = 1, 113e2ad626fSUlf Hansson }; 114e2ad626fSUlf Hansson 115e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_nooff = { 116e2ad626fSUlf Hansson .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) | 117e2ad626fSUlf Hansson BIT(OMAP_PRMD_RETENTION), 118e2ad626fSUlf Hansson .statechange = 1, 119e2ad626fSUlf Hansson .logicretstate = 1, 120e2ad626fSUlf Hansson }; 121e2ad626fSUlf Hansson 122e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_onoff_noauto = { 123e2ad626fSUlf Hansson .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF), 124e2ad626fSUlf Hansson .statechange = 1, 125e2ad626fSUlf Hansson }; 126e2ad626fSUlf Hansson 127e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_alwon = { 128e2ad626fSUlf Hansson .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE), 129e2ad626fSUlf Hansson }; 130e2ad626fSUlf Hansson 131e2ad626fSUlf Hansson static const struct omap_prm_domain_map omap_prm_reton = { 132e2ad626fSUlf Hansson .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION), 133e2ad626fSUlf Hansson .statechange = 1, 134e2ad626fSUlf Hansson .logicretstate = 1, 135e2ad626fSUlf Hansson }; 136e2ad626fSUlf Hansson 137e2ad626fSUlf Hansson static const struct omap_rst_map rst_map_0[] = { 138e2ad626fSUlf Hansson { .rst = 0, .st = 0 }, 139e2ad626fSUlf Hansson { .rst = -1 }, 140e2ad626fSUlf Hansson }; 141e2ad626fSUlf Hansson 142e2ad626fSUlf Hansson static const struct omap_rst_map rst_map_01[] = { 143e2ad626fSUlf Hansson { .rst = 0, .st = 0 }, 144e2ad626fSUlf Hansson { .rst = 1, .st = 1 }, 145e2ad626fSUlf Hansson { .rst = -1 }, 146e2ad626fSUlf Hansson }; 147e2ad626fSUlf Hansson 148e2ad626fSUlf Hansson static const struct omap_rst_map rst_map_012[] = { 149e2ad626fSUlf Hansson { .rst = 0, .st = 0 }, 150e2ad626fSUlf Hansson { .rst = 1, .st = 1 }, 151e2ad626fSUlf Hansson { .rst = 2, .st = 2 }, 152e2ad626fSUlf Hansson { .rst = -1 }, 153e2ad626fSUlf Hansson }; 154e2ad626fSUlf Hansson 155e2ad626fSUlf Hansson static const struct omap_prm_data omap4_prm_data[] = { 156e2ad626fSUlf Hansson { 157e2ad626fSUlf Hansson .name = "mpu", .base = 0x4a306300, 158e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, 159e2ad626fSUlf Hansson }, 160e2ad626fSUlf Hansson { 161e2ad626fSUlf Hansson .name = "tesla", .base = 0x4a306400, 162e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 163e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 164e2ad626fSUlf Hansson }, 165e2ad626fSUlf Hansson { 166e2ad626fSUlf Hansson .name = "abe", .base = 0x4a306500, 167e2ad626fSUlf Hansson .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all, 168e2ad626fSUlf Hansson }, 169e2ad626fSUlf Hansson { 170e2ad626fSUlf Hansson .name = "always_on_core", .base = 0x4a306600, 171e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 172e2ad626fSUlf Hansson }, 173e2ad626fSUlf Hansson { 174e2ad626fSUlf Hansson .name = "core", .base = 0x4a306700, 175e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, 176e2ad626fSUlf Hansson .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati", 177e2ad626fSUlf Hansson .rstmap = rst_map_012, 178e2ad626fSUlf Hansson .flags = OMAP_PRM_RET_WHEN_IDLE, 179e2ad626fSUlf Hansson }, 180e2ad626fSUlf Hansson { 181e2ad626fSUlf Hansson .name = "ivahd", .base = 0x4a306f00, 182e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 183e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 184e2ad626fSUlf Hansson }, 185e2ad626fSUlf Hansson { 186e2ad626fSUlf Hansson .name = "cam", .base = 0x4a307000, 187e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 188e2ad626fSUlf Hansson }, 189e2ad626fSUlf Hansson { 190e2ad626fSUlf Hansson .name = "dss", .base = 0x4a307100, 191e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact 192e2ad626fSUlf Hansson }, 193e2ad626fSUlf Hansson { 194e2ad626fSUlf Hansson .name = "gfx", .base = 0x4a307200, 195e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 196e2ad626fSUlf Hansson }, 197e2ad626fSUlf Hansson { 198e2ad626fSUlf Hansson .name = "l3init", .base = 0x4a307300, 199e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton 200e2ad626fSUlf Hansson }, 201e2ad626fSUlf Hansson { 202e2ad626fSUlf Hansson .name = "l4per", .base = 0x4a307400, 203e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, 204e2ad626fSUlf Hansson .flags = OMAP_PRM_RET_WHEN_IDLE, 205e2ad626fSUlf Hansson }, 206e2ad626fSUlf Hansson { 207e2ad626fSUlf Hansson .name = "cefuse", .base = 0x4a307600, 208e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 209e2ad626fSUlf Hansson }, 210e2ad626fSUlf Hansson { 211e2ad626fSUlf Hansson .name = "wkup", .base = 0x4a307700, 212e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon 213e2ad626fSUlf Hansson }, 214e2ad626fSUlf Hansson { 215e2ad626fSUlf Hansson .name = "emu", .base = 0x4a307900, 216e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 217e2ad626fSUlf Hansson }, 218e2ad626fSUlf Hansson { 219e2ad626fSUlf Hansson .name = "device", .base = 0x4a307b00, 220e2ad626fSUlf Hansson .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, 221e2ad626fSUlf Hansson .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM 222e2ad626fSUlf Hansson }, 223e2ad626fSUlf Hansson { }, 224e2ad626fSUlf Hansson }; 225e2ad626fSUlf Hansson 226e2ad626fSUlf Hansson static const struct omap_prm_data omap5_prm_data[] = { 227e2ad626fSUlf Hansson { 228e2ad626fSUlf Hansson .name = "mpu", .base = 0x4ae06300, 229e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, 230e2ad626fSUlf Hansson }, 231e2ad626fSUlf Hansson { 232e2ad626fSUlf Hansson .name = "dsp", .base = 0x4ae06400, 233e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 234e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 235e2ad626fSUlf Hansson }, 236e2ad626fSUlf Hansson { 237e2ad626fSUlf Hansson .name = "abe", .base = 0x4ae06500, 238e2ad626fSUlf Hansson .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff, 239e2ad626fSUlf Hansson }, 240e2ad626fSUlf Hansson { 241e2ad626fSUlf Hansson .name = "coreaon", .base = 0x4ae06600, 242e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon 243e2ad626fSUlf Hansson }, 244e2ad626fSUlf Hansson { 245e2ad626fSUlf Hansson .name = "core", .base = 0x4ae06700, 246e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, 247e2ad626fSUlf Hansson .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu", 248e2ad626fSUlf Hansson .rstmap = rst_map_012 249e2ad626fSUlf Hansson }, 250e2ad626fSUlf Hansson { 251e2ad626fSUlf Hansson .name = "iva", .base = 0x4ae07200, 252e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 253e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 254e2ad626fSUlf Hansson }, 255e2ad626fSUlf Hansson { 256e2ad626fSUlf Hansson .name = "cam", .base = 0x4ae07300, 257e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 258e2ad626fSUlf Hansson }, 259e2ad626fSUlf Hansson { 260e2ad626fSUlf Hansson .name = "dss", .base = 0x4ae07400, 261e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact 262e2ad626fSUlf Hansson }, 263e2ad626fSUlf Hansson { 264e2ad626fSUlf Hansson .name = "gpu", .base = 0x4ae07500, 265e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 266e2ad626fSUlf Hansson }, 267e2ad626fSUlf Hansson { 268e2ad626fSUlf Hansson .name = "l3init", .base = 0x4ae07600, 269e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton 270e2ad626fSUlf Hansson }, 271e2ad626fSUlf Hansson { 272e2ad626fSUlf Hansson .name = "custefuse", .base = 0x4ae07700, 273e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 274e2ad626fSUlf Hansson }, 275e2ad626fSUlf Hansson { 276e2ad626fSUlf Hansson .name = "wkupaon", .base = 0x4ae07800, 277e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon 278e2ad626fSUlf Hansson }, 279e2ad626fSUlf Hansson { 280e2ad626fSUlf Hansson .name = "emu", .base = 0x4ae07a00, 281e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto 282e2ad626fSUlf Hansson }, 283e2ad626fSUlf Hansson { 284e2ad626fSUlf Hansson .name = "device", .base = 0x4ae07c00, 285e2ad626fSUlf Hansson .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, 286e2ad626fSUlf Hansson .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM 287e2ad626fSUlf Hansson }, 288e2ad626fSUlf Hansson { }, 289e2ad626fSUlf Hansson }; 290e2ad626fSUlf Hansson 291e2ad626fSUlf Hansson static const struct omap_prm_data dra7_prm_data[] = { 292e2ad626fSUlf Hansson { 293e2ad626fSUlf Hansson .name = "mpu", .base = 0x4ae06300, 294e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton, 295e2ad626fSUlf Hansson }, 296e2ad626fSUlf Hansson { 297e2ad626fSUlf Hansson .name = "dsp1", .base = 0x4ae06400, 298e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 299e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01, 300e2ad626fSUlf Hansson }, 301e2ad626fSUlf Hansson { 302e2ad626fSUlf Hansson .name = "ipu", .base = 0x4ae06500, 303e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 304e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012, 305e2ad626fSUlf Hansson .clkdm_name = "ipu1" 306e2ad626fSUlf Hansson }, 307e2ad626fSUlf Hansson { 308e2ad626fSUlf Hansson .name = "coreaon", .base = 0x4ae06628, 309e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 310e2ad626fSUlf Hansson }, 311e2ad626fSUlf Hansson { 312e2ad626fSUlf Hansson .name = "core", .base = 0x4ae06700, 313e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 314e2ad626fSUlf Hansson .rstctrl = 0x210, .rstst = 0x214, .rstmap = rst_map_012, 315e2ad626fSUlf Hansson .clkdm_name = "ipu2" 316e2ad626fSUlf Hansson }, 317e2ad626fSUlf Hansson { 318e2ad626fSUlf Hansson .name = "iva", .base = 0x4ae06f00, 319e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 320e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012, 321e2ad626fSUlf Hansson }, 322e2ad626fSUlf Hansson { 323e2ad626fSUlf Hansson .name = "cam", .base = 0x4ae07000, 324e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 325e2ad626fSUlf Hansson }, 326e2ad626fSUlf Hansson { 327e2ad626fSUlf Hansson .name = "dss", .base = 0x4ae07100, 328e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 329e2ad626fSUlf Hansson }, 330e2ad626fSUlf Hansson { 331e2ad626fSUlf Hansson .name = "gpu", .base = 0x4ae07200, 332e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 333e2ad626fSUlf Hansson }, 334e2ad626fSUlf Hansson { 335e2ad626fSUlf Hansson .name = "l3init", .base = 0x4ae07300, 336e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 337e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01, 338e2ad626fSUlf Hansson .clkdm_name = "pcie" 339e2ad626fSUlf Hansson }, 340e2ad626fSUlf Hansson { 341e2ad626fSUlf Hansson .name = "l4per", .base = 0x4ae07400, 342e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 343e2ad626fSUlf Hansson }, 344e2ad626fSUlf Hansson { 345e2ad626fSUlf Hansson .name = "custefuse", .base = 0x4ae07600, 346e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 347e2ad626fSUlf Hansson }, 348e2ad626fSUlf Hansson { 349e2ad626fSUlf Hansson .name = "wkupaon", .base = 0x4ae07724, 350e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 351e2ad626fSUlf Hansson }, 352e2ad626fSUlf Hansson { 353e2ad626fSUlf Hansson .name = "emu", .base = 0x4ae07900, 354e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 355e2ad626fSUlf Hansson }, 356e2ad626fSUlf Hansson { 357e2ad626fSUlf Hansson .name = "dsp2", .base = 0x4ae07b00, 358e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 359e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 360e2ad626fSUlf Hansson }, 361e2ad626fSUlf Hansson { 362e2ad626fSUlf Hansson .name = "eve1", .base = 0x4ae07b40, 363e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 364e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 365e2ad626fSUlf Hansson }, 366e2ad626fSUlf Hansson { 367e2ad626fSUlf Hansson .name = "eve2", .base = 0x4ae07b80, 368e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 369e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 370e2ad626fSUlf Hansson }, 371e2ad626fSUlf Hansson { 372e2ad626fSUlf Hansson .name = "eve3", .base = 0x4ae07bc0, 373e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 374e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 375e2ad626fSUlf Hansson }, 376e2ad626fSUlf Hansson { 377e2ad626fSUlf Hansson .name = "eve4", .base = 0x4ae07c00, 378e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 379e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 380e2ad626fSUlf Hansson }, 381e2ad626fSUlf Hansson { 382e2ad626fSUlf Hansson .name = "rtc", .base = 0x4ae07c60, 383e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 384e2ad626fSUlf Hansson }, 385e2ad626fSUlf Hansson { 386e2ad626fSUlf Hansson .name = "vpe", .base = 0x4ae07c80, 387e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 388e2ad626fSUlf Hansson }, 389e2ad626fSUlf Hansson { }, 390e2ad626fSUlf Hansson }; 391e2ad626fSUlf Hansson 392e2ad626fSUlf Hansson static const struct omap_rst_map am3_per_rst_map[] = { 393e2ad626fSUlf Hansson { .rst = 1 }, 394e2ad626fSUlf Hansson { .rst = -1 }, 395e2ad626fSUlf Hansson }; 396e2ad626fSUlf Hansson 397e2ad626fSUlf Hansson static const struct omap_rst_map am3_wkup_rst_map[] = { 398e2ad626fSUlf Hansson { .rst = 3, .st = 5 }, 399e2ad626fSUlf Hansson { .rst = -1 }, 400e2ad626fSUlf Hansson }; 401e2ad626fSUlf Hansson 402e2ad626fSUlf Hansson static const struct omap_prm_data am3_prm_data[] = { 403e2ad626fSUlf Hansson { 404e2ad626fSUlf Hansson .name = "per", .base = 0x44e00c00, 405e2ad626fSUlf Hansson .pwrstctrl = 0xc, .pwrstst = 0x8, .dmap = &omap_prm_noinact, 406e2ad626fSUlf Hansson .rstctrl = 0x0, .rstmap = am3_per_rst_map, 407e2ad626fSUlf Hansson .flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp" 408e2ad626fSUlf Hansson }, 409e2ad626fSUlf Hansson { 410e2ad626fSUlf Hansson .name = "wkup", .base = 0x44e00d00, 411e2ad626fSUlf Hansson .pwrstctrl = 0x4, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 412e2ad626fSUlf Hansson .rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map, 413e2ad626fSUlf Hansson .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM 414e2ad626fSUlf Hansson }, 415e2ad626fSUlf Hansson { 416e2ad626fSUlf Hansson .name = "mpu", .base = 0x44e00e00, 417e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 418e2ad626fSUlf Hansson }, 419e2ad626fSUlf Hansson { 420e2ad626fSUlf Hansson .name = "device", .base = 0x44e00f00, 421e2ad626fSUlf Hansson .rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01, 422e2ad626fSUlf Hansson .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM 423e2ad626fSUlf Hansson }, 424e2ad626fSUlf Hansson { 425e2ad626fSUlf Hansson .name = "rtc", .base = 0x44e01000, 426e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 427e2ad626fSUlf Hansson }, 428e2ad626fSUlf Hansson { 429e2ad626fSUlf Hansson .name = "gfx", .base = 0x44e01100, 430e2ad626fSUlf Hansson .pwrstctrl = 0, .pwrstst = 0x10, .dmap = &omap_prm_noinact, 431e2ad626fSUlf Hansson .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3", 432e2ad626fSUlf Hansson }, 433e2ad626fSUlf Hansson { 434e2ad626fSUlf Hansson .name = "cefuse", .base = 0x44e01200, 435e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 436e2ad626fSUlf Hansson }, 437e2ad626fSUlf Hansson { }, 438e2ad626fSUlf Hansson }; 439e2ad626fSUlf Hansson 440e2ad626fSUlf Hansson static const struct omap_rst_map am4_per_rst_map[] = { 441e2ad626fSUlf Hansson { .rst = 1, .st = 0 }, 442e2ad626fSUlf Hansson { .rst = -1 }, 443e2ad626fSUlf Hansson }; 444e2ad626fSUlf Hansson 445e2ad626fSUlf Hansson static const struct omap_rst_map am4_device_rst_map[] = { 446e2ad626fSUlf Hansson { .rst = 0, .st = 1 }, 447e2ad626fSUlf Hansson { .rst = 1, .st = 0 }, 448e2ad626fSUlf Hansson { .rst = -1 }, 449e2ad626fSUlf Hansson }; 450e2ad626fSUlf Hansson 451e2ad626fSUlf Hansson static const struct omap_prm_data am4_prm_data[] = { 452e2ad626fSUlf Hansson { 453e2ad626fSUlf Hansson .name = "mpu", .base = 0x44df0300, 454e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 455e2ad626fSUlf Hansson }, 456e2ad626fSUlf Hansson { 457e2ad626fSUlf Hansson .name = "gfx", .base = 0x44df0400, 458e2ad626fSUlf Hansson .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 459e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3", 460e2ad626fSUlf Hansson }, 461e2ad626fSUlf Hansson { 462e2ad626fSUlf Hansson .name = "rtc", .base = 0x44df0500, 463e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 464e2ad626fSUlf Hansson }, 465e2ad626fSUlf Hansson { 466e2ad626fSUlf Hansson .name = "tamper", .base = 0x44df0600, 467e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 468e2ad626fSUlf Hansson }, 469e2ad626fSUlf Hansson { 470e2ad626fSUlf Hansson .name = "cefuse", .base = 0x44df0700, 471e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 472e2ad626fSUlf Hansson }, 473e2ad626fSUlf Hansson { 474e2ad626fSUlf Hansson .name = "per", .base = 0x44df0800, 475e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact, 476e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map, 477e2ad626fSUlf Hansson .clkdm_name = "pruss_ocp" 478e2ad626fSUlf Hansson }, 479e2ad626fSUlf Hansson { 480e2ad626fSUlf Hansson .name = "wkup", .base = 0x44df2000, 481e2ad626fSUlf Hansson .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon, 482e2ad626fSUlf Hansson .rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map, 483e2ad626fSUlf Hansson .flags = OMAP_PRM_HAS_NO_CLKDM 484e2ad626fSUlf Hansson }, 485e2ad626fSUlf Hansson { 486e2ad626fSUlf Hansson .name = "device", .base = 0x44df4000, 487e2ad626fSUlf Hansson .rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map, 488e2ad626fSUlf Hansson .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM 489e2ad626fSUlf Hansson }, 490e2ad626fSUlf Hansson { }, 491e2ad626fSUlf Hansson }; 492e2ad626fSUlf Hansson 493e2ad626fSUlf Hansson static const struct of_device_id omap_prm_id_table[] = { 494e2ad626fSUlf Hansson { .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data }, 495e2ad626fSUlf Hansson { .compatible = "ti,omap5-prm-inst", .data = omap5_prm_data }, 496e2ad626fSUlf Hansson { .compatible = "ti,dra7-prm-inst", .data = dra7_prm_data }, 497e2ad626fSUlf Hansson { .compatible = "ti,am3-prm-inst", .data = am3_prm_data }, 498e2ad626fSUlf Hansson { .compatible = "ti,am4-prm-inst", .data = am4_prm_data }, 499e2ad626fSUlf Hansson { }, 500e2ad626fSUlf Hansson }; 501e2ad626fSUlf Hansson 502e2ad626fSUlf Hansson #ifdef DEBUG 503e2ad626fSUlf Hansson static void omap_prm_domain_show_state(struct omap_prm_domain *prmd, 504e2ad626fSUlf Hansson const char *desc) 505e2ad626fSUlf Hansson { 506e2ad626fSUlf Hansson dev_dbg(prmd->dev, "%s %s: %08x/%08x\n", 507e2ad626fSUlf Hansson prmd->pd.name, desc, 508e2ad626fSUlf Hansson readl_relaxed(prmd->prm->base + prmd->pwrstctrl), 509e2ad626fSUlf Hansson readl_relaxed(prmd->prm->base + prmd->pwrstst)); 510e2ad626fSUlf Hansson } 511e2ad626fSUlf Hansson #else 512e2ad626fSUlf Hansson static inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd, 513e2ad626fSUlf Hansson const char *desc) 514e2ad626fSUlf Hansson { 515e2ad626fSUlf Hansson } 516e2ad626fSUlf Hansson #endif 517e2ad626fSUlf Hansson 518e2ad626fSUlf Hansson static int omap_prm_domain_power_on(struct generic_pm_domain *domain) 519e2ad626fSUlf Hansson { 520e2ad626fSUlf Hansson struct omap_prm_domain *prmd; 521e2ad626fSUlf Hansson int ret; 522e2ad626fSUlf Hansson u32 v, mode; 523e2ad626fSUlf Hansson 524e2ad626fSUlf Hansson prmd = genpd_to_prm_domain(domain); 525e2ad626fSUlf Hansson if (!prmd->cap) 526e2ad626fSUlf Hansson return 0; 527e2ad626fSUlf Hansson 528e2ad626fSUlf Hansson omap_prm_domain_show_state(prmd, "on: previous state"); 529e2ad626fSUlf Hansson 530e2ad626fSUlf Hansson if (prmd->pwrstctrl_saved) 531e2ad626fSUlf Hansson v = prmd->pwrstctrl_saved; 532e2ad626fSUlf Hansson else 533e2ad626fSUlf Hansson v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); 534e2ad626fSUlf Hansson 535e2ad626fSUlf Hansson if (prmd->prm->data->flags & OMAP_PRM_RET_WHEN_IDLE) 536e2ad626fSUlf Hansson mode = OMAP_PRMD_RETENTION; 537e2ad626fSUlf Hansson else 538e2ad626fSUlf Hansson mode = OMAP_PRMD_ON_ACTIVE; 539e2ad626fSUlf Hansson 540e2ad626fSUlf Hansson writel_relaxed((v & ~PRM_POWERSTATE_MASK) | mode, 541e2ad626fSUlf Hansson prmd->prm->base + prmd->pwrstctrl); 542e2ad626fSUlf Hansson 543e2ad626fSUlf Hansson /* wait for the transition bit to get cleared */ 544e2ad626fSUlf Hansson ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst, 545e2ad626fSUlf Hansson v, !(v & PRM_ST_INTRANSITION), 1, 546e2ad626fSUlf Hansson PRM_STATE_MAX_WAIT); 547e2ad626fSUlf Hansson if (ret) 548e2ad626fSUlf Hansson dev_err(prmd->dev, "%s: %s timed out\n", 549e2ad626fSUlf Hansson prmd->pd.name, __func__); 550e2ad626fSUlf Hansson 551e2ad626fSUlf Hansson omap_prm_domain_show_state(prmd, "on: new state"); 552e2ad626fSUlf Hansson 553e2ad626fSUlf Hansson return ret; 554e2ad626fSUlf Hansson } 555e2ad626fSUlf Hansson 556e2ad626fSUlf Hansson /* No need to check for holes in the mask for the lowest mode */ 557e2ad626fSUlf Hansson static int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd) 558e2ad626fSUlf Hansson { 559e2ad626fSUlf Hansson return __ffs(prmd->cap->usable_modes); 560e2ad626fSUlf Hansson } 561e2ad626fSUlf Hansson 562e2ad626fSUlf Hansson static int omap_prm_domain_power_off(struct generic_pm_domain *domain) 563e2ad626fSUlf Hansson { 564e2ad626fSUlf Hansson struct omap_prm_domain *prmd; 565e2ad626fSUlf Hansson int ret; 566e2ad626fSUlf Hansson u32 v; 567e2ad626fSUlf Hansson 568e2ad626fSUlf Hansson prmd = genpd_to_prm_domain(domain); 569e2ad626fSUlf Hansson if (!prmd->cap) 570e2ad626fSUlf Hansson return 0; 571e2ad626fSUlf Hansson 572e2ad626fSUlf Hansson omap_prm_domain_show_state(prmd, "off: previous state"); 573e2ad626fSUlf Hansson 574e2ad626fSUlf Hansson v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); 575e2ad626fSUlf Hansson prmd->pwrstctrl_saved = v; 576e2ad626fSUlf Hansson 577e2ad626fSUlf Hansson v &= ~PRM_POWERSTATE_MASK; 578e2ad626fSUlf Hansson v |= omap_prm_domain_find_lowest(prmd); 579e2ad626fSUlf Hansson 580e2ad626fSUlf Hansson if (prmd->cap->statechange) 581e2ad626fSUlf Hansson v |= PRM_LOWPOWERSTATECHANGE; 582e2ad626fSUlf Hansson if (prmd->cap->logicretstate) 583e2ad626fSUlf Hansson v &= ~PRM_LOGICRETSTATE; 584e2ad626fSUlf Hansson else 585e2ad626fSUlf Hansson v |= PRM_LOGICRETSTATE; 586e2ad626fSUlf Hansson 587e2ad626fSUlf Hansson writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl); 588e2ad626fSUlf Hansson 589e2ad626fSUlf Hansson /* wait for the transition bit to get cleared */ 590e2ad626fSUlf Hansson ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst, 591e2ad626fSUlf Hansson v, !(v & PRM_ST_INTRANSITION), 1, 592e2ad626fSUlf Hansson PRM_STATE_MAX_WAIT); 593e2ad626fSUlf Hansson if (ret) 594e2ad626fSUlf Hansson dev_warn(prmd->dev, "%s: %s timed out\n", 595e2ad626fSUlf Hansson __func__, prmd->pd.name); 596e2ad626fSUlf Hansson 597e2ad626fSUlf Hansson omap_prm_domain_show_state(prmd, "off: new state"); 598e2ad626fSUlf Hansson 599e2ad626fSUlf Hansson return 0; 600e2ad626fSUlf Hansson } 601e2ad626fSUlf Hansson 602e2ad626fSUlf Hansson /* 603e2ad626fSUlf Hansson * Note that ti-sysc already manages the module clocks separately so 604e2ad626fSUlf Hansson * no need to manage those. Interconnect instances need clocks managed 605e2ad626fSUlf Hansson * for simple-pm-bus. 606e2ad626fSUlf Hansson */ 607e2ad626fSUlf Hansson static int omap_prm_domain_attach_clock(struct device *dev, 608e2ad626fSUlf Hansson struct omap_prm_domain *prmd) 609e2ad626fSUlf Hansson { 610e2ad626fSUlf Hansson struct device_node *np = dev->of_node; 611e2ad626fSUlf Hansson int error; 612e2ad626fSUlf Hansson 613e2ad626fSUlf Hansson if (!of_device_is_compatible(np, "simple-pm-bus")) 614e2ad626fSUlf Hansson return 0; 615e2ad626fSUlf Hansson 616e2ad626fSUlf Hansson if (!of_property_read_bool(np, "clocks")) 617e2ad626fSUlf Hansson return 0; 618e2ad626fSUlf Hansson 619e2ad626fSUlf Hansson error = pm_clk_create(dev); 620e2ad626fSUlf Hansson if (error) 621e2ad626fSUlf Hansson return error; 622e2ad626fSUlf Hansson 623e2ad626fSUlf Hansson error = of_pm_clk_add_clks(dev); 624e2ad626fSUlf Hansson if (error < 0) { 625e2ad626fSUlf Hansson pm_clk_destroy(dev); 626e2ad626fSUlf Hansson return error; 627e2ad626fSUlf Hansson } 628e2ad626fSUlf Hansson 629e2ad626fSUlf Hansson prmd->uses_pm_clk = 1; 630e2ad626fSUlf Hansson 631e2ad626fSUlf Hansson return 0; 632e2ad626fSUlf Hansson } 633e2ad626fSUlf Hansson 634e2ad626fSUlf Hansson static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, 635e2ad626fSUlf Hansson struct device *dev) 636e2ad626fSUlf Hansson { 637e2ad626fSUlf Hansson struct generic_pm_domain_data *genpd_data; 638e2ad626fSUlf Hansson struct of_phandle_args pd_args; 639e2ad626fSUlf Hansson struct omap_prm_domain *prmd; 640e2ad626fSUlf Hansson struct device_node *np; 641e2ad626fSUlf Hansson int ret; 642e2ad626fSUlf Hansson 643e2ad626fSUlf Hansson prmd = genpd_to_prm_domain(domain); 644e2ad626fSUlf Hansson np = dev->of_node; 645e2ad626fSUlf Hansson 646e2ad626fSUlf Hansson ret = of_parse_phandle_with_args(np, "power-domains", 647e2ad626fSUlf Hansson "#power-domain-cells", 0, &pd_args); 648e2ad626fSUlf Hansson if (ret < 0) 649e2ad626fSUlf Hansson return ret; 650e2ad626fSUlf Hansson 651e2ad626fSUlf Hansson if (pd_args.args_count != 0) 652e2ad626fSUlf Hansson dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", 653e2ad626fSUlf Hansson prmd->pd.name, pd_args.args_count); 654e2ad626fSUlf Hansson 655e2ad626fSUlf Hansson genpd_data = dev_gpd_data(dev); 656e2ad626fSUlf Hansson genpd_data->data = NULL; 657e2ad626fSUlf Hansson 658e2ad626fSUlf Hansson ret = omap_prm_domain_attach_clock(dev, prmd); 659e2ad626fSUlf Hansson if (ret) 660e2ad626fSUlf Hansson return ret; 661e2ad626fSUlf Hansson 662e2ad626fSUlf Hansson return 0; 663e2ad626fSUlf Hansson } 664e2ad626fSUlf Hansson 665e2ad626fSUlf Hansson static void omap_prm_domain_detach_dev(struct generic_pm_domain *domain, 666e2ad626fSUlf Hansson struct device *dev) 667e2ad626fSUlf Hansson { 668e2ad626fSUlf Hansson struct generic_pm_domain_data *genpd_data; 669e2ad626fSUlf Hansson struct omap_prm_domain *prmd; 670e2ad626fSUlf Hansson 671e2ad626fSUlf Hansson prmd = genpd_to_prm_domain(domain); 672e2ad626fSUlf Hansson if (prmd->uses_pm_clk) 673e2ad626fSUlf Hansson pm_clk_destroy(dev); 674e2ad626fSUlf Hansson genpd_data = dev_gpd_data(dev); 675e2ad626fSUlf Hansson genpd_data->data = NULL; 676e2ad626fSUlf Hansson } 677e2ad626fSUlf Hansson 678e2ad626fSUlf Hansson static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm) 679e2ad626fSUlf Hansson { 680e2ad626fSUlf Hansson struct omap_prm_domain *prmd; 681e2ad626fSUlf Hansson struct device_node *np = dev->of_node; 682e2ad626fSUlf Hansson const struct omap_prm_data *data; 683e2ad626fSUlf Hansson const char *name; 684e2ad626fSUlf Hansson int error; 685e2ad626fSUlf Hansson 686e2ad626fSUlf Hansson if (!of_property_present(dev->of_node, "#power-domain-cells")) 687e2ad626fSUlf Hansson return 0; 688e2ad626fSUlf Hansson 689e2ad626fSUlf Hansson of_node_put(dev->of_node); 690e2ad626fSUlf Hansson 691e2ad626fSUlf Hansson prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL); 692e2ad626fSUlf Hansson if (!prmd) 693e2ad626fSUlf Hansson return -ENOMEM; 694e2ad626fSUlf Hansson 695e2ad626fSUlf Hansson data = prm->data; 696e2ad626fSUlf Hansson name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s", 697e2ad626fSUlf Hansson data->name); 698*ce666cecSKunwu Chan if (!name) 699*ce666cecSKunwu Chan return -ENOMEM; 700e2ad626fSUlf Hansson 701e2ad626fSUlf Hansson prmd->dev = dev; 702e2ad626fSUlf Hansson prmd->prm = prm; 703e2ad626fSUlf Hansson prmd->cap = prmd->prm->data->dmap; 704e2ad626fSUlf Hansson prmd->pwrstctrl = prmd->prm->data->pwrstctrl; 705e2ad626fSUlf Hansson prmd->pwrstst = prmd->prm->data->pwrstst; 706e2ad626fSUlf Hansson 707e2ad626fSUlf Hansson prmd->pd.name = name; 708e2ad626fSUlf Hansson prmd->pd.power_on = omap_prm_domain_power_on; 709e2ad626fSUlf Hansson prmd->pd.power_off = omap_prm_domain_power_off; 710e2ad626fSUlf Hansson prmd->pd.attach_dev = omap_prm_domain_attach_dev; 711e2ad626fSUlf Hansson prmd->pd.detach_dev = omap_prm_domain_detach_dev; 712e2ad626fSUlf Hansson prmd->pd.flags = GENPD_FLAG_PM_CLK; 713e2ad626fSUlf Hansson 714e2ad626fSUlf Hansson pm_genpd_init(&prmd->pd, NULL, true); 715e2ad626fSUlf Hansson error = of_genpd_add_provider_simple(np, &prmd->pd); 716e2ad626fSUlf Hansson if (error) 717e2ad626fSUlf Hansson pm_genpd_remove(&prmd->pd); 718e2ad626fSUlf Hansson else 719e2ad626fSUlf Hansson prm->prmd = prmd; 720e2ad626fSUlf Hansson 721e2ad626fSUlf Hansson return error; 722e2ad626fSUlf Hansson } 723e2ad626fSUlf Hansson 724e2ad626fSUlf Hansson static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id) 725e2ad626fSUlf Hansson { 726e2ad626fSUlf Hansson if (reset->mask & BIT(id)) 727e2ad626fSUlf Hansson return true; 728e2ad626fSUlf Hansson 729e2ad626fSUlf Hansson return false; 730e2ad626fSUlf Hansson } 731e2ad626fSUlf Hansson 732e2ad626fSUlf Hansson static int omap_reset_get_st_bit(struct omap_reset_data *reset, 733e2ad626fSUlf Hansson unsigned long id) 734e2ad626fSUlf Hansson { 735e2ad626fSUlf Hansson const struct omap_rst_map *map = reset->prm->data->rstmap; 736e2ad626fSUlf Hansson 737e2ad626fSUlf Hansson while (map->rst >= 0) { 738e2ad626fSUlf Hansson if (map->rst == id) 739e2ad626fSUlf Hansson return map->st; 740e2ad626fSUlf Hansson 741e2ad626fSUlf Hansson map++; 742e2ad626fSUlf Hansson } 743e2ad626fSUlf Hansson 744e2ad626fSUlf Hansson return id; 745e2ad626fSUlf Hansson } 746e2ad626fSUlf Hansson 747e2ad626fSUlf Hansson static int omap_reset_status(struct reset_controller_dev *rcdev, 748e2ad626fSUlf Hansson unsigned long id) 749e2ad626fSUlf Hansson { 750e2ad626fSUlf Hansson struct omap_reset_data *reset = to_omap_reset_data(rcdev); 751e2ad626fSUlf Hansson u32 v; 752e2ad626fSUlf Hansson int st_bit = omap_reset_get_st_bit(reset, id); 753e2ad626fSUlf Hansson bool has_rstst = reset->prm->data->rstst || 754e2ad626fSUlf Hansson (reset->prm->data->flags & OMAP_PRM_HAS_RSTST); 755e2ad626fSUlf Hansson 756e2ad626fSUlf Hansson /* Check if we have rstst */ 757e2ad626fSUlf Hansson if (!has_rstst) 758e2ad626fSUlf Hansson return -ENOTSUPP; 759e2ad626fSUlf Hansson 760e2ad626fSUlf Hansson /* Check if hw reset line is asserted */ 761e2ad626fSUlf Hansson v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 762e2ad626fSUlf Hansson if (v & BIT(id)) 763e2ad626fSUlf Hansson return 1; 764e2ad626fSUlf Hansson 765e2ad626fSUlf Hansson /* 766e2ad626fSUlf Hansson * Check reset status, high value means reset sequence has been 767e2ad626fSUlf Hansson * completed successfully so we can return 0 here (reset deasserted) 768e2ad626fSUlf Hansson */ 769e2ad626fSUlf Hansson v = readl_relaxed(reset->prm->base + reset->prm->data->rstst); 770e2ad626fSUlf Hansson v >>= st_bit; 771e2ad626fSUlf Hansson v &= 1; 772e2ad626fSUlf Hansson 773e2ad626fSUlf Hansson return !v; 774e2ad626fSUlf Hansson } 775e2ad626fSUlf Hansson 776e2ad626fSUlf Hansson static int omap_reset_assert(struct reset_controller_dev *rcdev, 777e2ad626fSUlf Hansson unsigned long id) 778e2ad626fSUlf Hansson { 779e2ad626fSUlf Hansson struct omap_reset_data *reset = to_omap_reset_data(rcdev); 780e2ad626fSUlf Hansson u32 v; 781e2ad626fSUlf Hansson unsigned long flags; 782e2ad626fSUlf Hansson 783e2ad626fSUlf Hansson /* assert the reset control line */ 784e2ad626fSUlf Hansson spin_lock_irqsave(&reset->lock, flags); 785e2ad626fSUlf Hansson v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 786e2ad626fSUlf Hansson v |= 1 << id; 787e2ad626fSUlf Hansson writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl); 788e2ad626fSUlf Hansson spin_unlock_irqrestore(&reset->lock, flags); 789e2ad626fSUlf Hansson 790e2ad626fSUlf Hansson return 0; 791e2ad626fSUlf Hansson } 792e2ad626fSUlf Hansson 793e2ad626fSUlf Hansson static int omap_reset_deassert(struct reset_controller_dev *rcdev, 794e2ad626fSUlf Hansson unsigned long id) 795e2ad626fSUlf Hansson { 796e2ad626fSUlf Hansson struct omap_reset_data *reset = to_omap_reset_data(rcdev); 797e2ad626fSUlf Hansson u32 v; 798e2ad626fSUlf Hansson int st_bit; 799e2ad626fSUlf Hansson bool has_rstst; 800e2ad626fSUlf Hansson unsigned long flags; 801e2ad626fSUlf Hansson struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev); 802e2ad626fSUlf Hansson int ret = 0; 803e2ad626fSUlf Hansson 804e2ad626fSUlf Hansson /* Nothing to do if the reset is already deasserted */ 805e2ad626fSUlf Hansson if (!omap_reset_status(rcdev, id)) 806e2ad626fSUlf Hansson return 0; 807e2ad626fSUlf Hansson 808e2ad626fSUlf Hansson has_rstst = reset->prm->data->rstst || 809e2ad626fSUlf Hansson (reset->prm->data->flags & OMAP_PRM_HAS_RSTST); 810e2ad626fSUlf Hansson 811e2ad626fSUlf Hansson if (has_rstst) { 812e2ad626fSUlf Hansson st_bit = omap_reset_get_st_bit(reset, id); 813e2ad626fSUlf Hansson 814e2ad626fSUlf Hansson /* Clear the reset status by writing 1 to the status bit */ 815e2ad626fSUlf Hansson v = 1 << st_bit; 816e2ad626fSUlf Hansson writel_relaxed(v, reset->prm->base + reset->prm->data->rstst); 817e2ad626fSUlf Hansson } 818e2ad626fSUlf Hansson 819e2ad626fSUlf Hansson if (reset->clkdm) 820e2ad626fSUlf Hansson pdata->clkdm_deny_idle(reset->clkdm); 821e2ad626fSUlf Hansson 822e2ad626fSUlf Hansson /* de-assert the reset control line */ 823e2ad626fSUlf Hansson spin_lock_irqsave(&reset->lock, flags); 824e2ad626fSUlf Hansson v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 825e2ad626fSUlf Hansson v &= ~(1 << id); 826e2ad626fSUlf Hansson writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl); 827e2ad626fSUlf Hansson spin_unlock_irqrestore(&reset->lock, flags); 828e2ad626fSUlf Hansson 829e2ad626fSUlf Hansson /* wait for the reset bit to clear */ 830e2ad626fSUlf Hansson ret = readl_relaxed_poll_timeout_atomic(reset->prm->base + 831e2ad626fSUlf Hansson reset->prm->data->rstctrl, 832e2ad626fSUlf Hansson v, !(v & BIT(id)), 1, 833e2ad626fSUlf Hansson OMAP_RESET_MAX_WAIT); 834e2ad626fSUlf Hansson if (ret) 835e2ad626fSUlf Hansson pr_err("%s: timedout waiting for %s:%lu\n", __func__, 836e2ad626fSUlf Hansson reset->prm->data->name, id); 837e2ad626fSUlf Hansson 838e2ad626fSUlf Hansson /* wait for the status to be set */ 839e2ad626fSUlf Hansson if (has_rstst) { 840e2ad626fSUlf Hansson ret = readl_relaxed_poll_timeout_atomic(reset->prm->base + 841e2ad626fSUlf Hansson reset->prm->data->rstst, 842e2ad626fSUlf Hansson v, v & BIT(st_bit), 1, 843e2ad626fSUlf Hansson OMAP_RESET_MAX_WAIT); 844e2ad626fSUlf Hansson if (ret) 845e2ad626fSUlf Hansson pr_err("%s: timedout waiting for %s:%lu\n", __func__, 846e2ad626fSUlf Hansson reset->prm->data->name, id); 847e2ad626fSUlf Hansson } 848e2ad626fSUlf Hansson 849e2ad626fSUlf Hansson if (reset->clkdm) 850e2ad626fSUlf Hansson pdata->clkdm_allow_idle(reset->clkdm); 851e2ad626fSUlf Hansson 852e2ad626fSUlf Hansson return ret; 853e2ad626fSUlf Hansson } 854e2ad626fSUlf Hansson 855e2ad626fSUlf Hansson static const struct reset_control_ops omap_reset_ops = { 856e2ad626fSUlf Hansson .assert = omap_reset_assert, 857e2ad626fSUlf Hansson .deassert = omap_reset_deassert, 858e2ad626fSUlf Hansson .status = omap_reset_status, 859e2ad626fSUlf Hansson }; 860e2ad626fSUlf Hansson 861e2ad626fSUlf Hansson static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev, 862e2ad626fSUlf Hansson const struct of_phandle_args *reset_spec) 863e2ad626fSUlf Hansson { 864e2ad626fSUlf Hansson struct omap_reset_data *reset = to_omap_reset_data(rcdev); 865e2ad626fSUlf Hansson 866e2ad626fSUlf Hansson if (!_is_valid_reset(reset, reset_spec->args[0])) 867e2ad626fSUlf Hansson return -EINVAL; 868e2ad626fSUlf Hansson 869e2ad626fSUlf Hansson return reset_spec->args[0]; 870e2ad626fSUlf Hansson } 871e2ad626fSUlf Hansson 872e2ad626fSUlf Hansson static int omap_prm_reset_init(struct platform_device *pdev, 873e2ad626fSUlf Hansson struct omap_prm *prm) 874e2ad626fSUlf Hansson { 875e2ad626fSUlf Hansson struct omap_reset_data *reset; 876e2ad626fSUlf Hansson const struct omap_rst_map *map; 877e2ad626fSUlf Hansson struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev); 878e2ad626fSUlf Hansson char buf[32]; 879e2ad626fSUlf Hansson u32 v; 880e2ad626fSUlf Hansson 881e2ad626fSUlf Hansson /* 882e2ad626fSUlf Hansson * Check if we have controllable resets. If either rstctrl is non-zero 883e2ad626fSUlf Hansson * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register 884e2ad626fSUlf Hansson * for the domain. 885e2ad626fSUlf Hansson */ 886e2ad626fSUlf Hansson if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL)) 887e2ad626fSUlf Hansson return 0; 888e2ad626fSUlf Hansson 889e2ad626fSUlf Hansson /* Check if we have the pdata callbacks in place */ 890e2ad626fSUlf Hansson if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle || 891e2ad626fSUlf Hansson !pdata->clkdm_allow_idle) 892e2ad626fSUlf Hansson return -EINVAL; 893e2ad626fSUlf Hansson 894e2ad626fSUlf Hansson map = prm->data->rstmap; 895e2ad626fSUlf Hansson if (!map) 896e2ad626fSUlf Hansson return -EINVAL; 897e2ad626fSUlf Hansson 898e2ad626fSUlf Hansson reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); 899e2ad626fSUlf Hansson if (!reset) 900e2ad626fSUlf Hansson return -ENOMEM; 901e2ad626fSUlf Hansson 902e2ad626fSUlf Hansson reset->rcdev.owner = THIS_MODULE; 903e2ad626fSUlf Hansson reset->rcdev.ops = &omap_reset_ops; 904e2ad626fSUlf Hansson reset->rcdev.of_node = pdev->dev.of_node; 905e2ad626fSUlf Hansson reset->rcdev.nr_resets = OMAP_MAX_RESETS; 906e2ad626fSUlf Hansson reset->rcdev.of_xlate = omap_prm_reset_xlate; 907e2ad626fSUlf Hansson reset->rcdev.of_reset_n_cells = 1; 908e2ad626fSUlf Hansson reset->dev = &pdev->dev; 909e2ad626fSUlf Hansson spin_lock_init(&reset->lock); 910e2ad626fSUlf Hansson 911e2ad626fSUlf Hansson reset->prm = prm; 912e2ad626fSUlf Hansson 913e2ad626fSUlf Hansson sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name : 914e2ad626fSUlf Hansson prm->data->name); 915e2ad626fSUlf Hansson 916e2ad626fSUlf Hansson if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) { 917e2ad626fSUlf Hansson reset->clkdm = pdata->clkdm_lookup(buf); 918e2ad626fSUlf Hansson if (!reset->clkdm) 919e2ad626fSUlf Hansson return -EINVAL; 920e2ad626fSUlf Hansson } 921e2ad626fSUlf Hansson 922e2ad626fSUlf Hansson while (map->rst >= 0) { 923e2ad626fSUlf Hansson reset->mask |= BIT(map->rst); 924e2ad626fSUlf Hansson map++; 925e2ad626fSUlf Hansson } 926e2ad626fSUlf Hansson 927e2ad626fSUlf Hansson /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */ 928e2ad626fSUlf Hansson if (prm->data->rstmap == rst_map_012) { 929e2ad626fSUlf Hansson v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 930e2ad626fSUlf Hansson if ((v & reset->mask) != reset->mask) { 931e2ad626fSUlf Hansson dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v); 932e2ad626fSUlf Hansson writel_relaxed(reset->mask, reset->prm->base + 933e2ad626fSUlf Hansson reset->prm->data->rstctrl); 934e2ad626fSUlf Hansson } 935e2ad626fSUlf Hansson } 936e2ad626fSUlf Hansson 937e2ad626fSUlf Hansson return devm_reset_controller_register(&pdev->dev, &reset->rcdev); 938e2ad626fSUlf Hansson } 939e2ad626fSUlf Hansson 940e2ad626fSUlf Hansson static int omap_prm_probe(struct platform_device *pdev) 941e2ad626fSUlf Hansson { 942e2ad626fSUlf Hansson struct resource *res; 943e2ad626fSUlf Hansson const struct omap_prm_data *data; 944e2ad626fSUlf Hansson struct omap_prm *prm; 945e2ad626fSUlf Hansson int ret; 946e2ad626fSUlf Hansson 947e2ad626fSUlf Hansson data = of_device_get_match_data(&pdev->dev); 948e2ad626fSUlf Hansson if (!data) 949e2ad626fSUlf Hansson return -ENOTSUPP; 950e2ad626fSUlf Hansson 951e2ad626fSUlf Hansson prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL); 952e2ad626fSUlf Hansson if (!prm) 953e2ad626fSUlf Hansson return -ENOMEM; 954e2ad626fSUlf Hansson 955e2ad626fSUlf Hansson prm->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 956e2ad626fSUlf Hansson if (IS_ERR(prm->base)) 957e2ad626fSUlf Hansson return PTR_ERR(prm->base); 958e2ad626fSUlf Hansson 959e2ad626fSUlf Hansson while (data->base != res->start) { 960e2ad626fSUlf Hansson if (!data->base) 961e2ad626fSUlf Hansson return -EINVAL; 962e2ad626fSUlf Hansson data++; 963e2ad626fSUlf Hansson } 964e2ad626fSUlf Hansson 965e2ad626fSUlf Hansson prm->data = data; 966e2ad626fSUlf Hansson 967e2ad626fSUlf Hansson ret = omap_prm_domain_init(&pdev->dev, prm); 968e2ad626fSUlf Hansson if (ret) 969e2ad626fSUlf Hansson return ret; 970e2ad626fSUlf Hansson 971e2ad626fSUlf Hansson ret = omap_prm_reset_init(pdev, prm); 972e2ad626fSUlf Hansson if (ret) 973e2ad626fSUlf Hansson goto err_domain; 974e2ad626fSUlf Hansson 975e2ad626fSUlf Hansson return 0; 976e2ad626fSUlf Hansson 977e2ad626fSUlf Hansson err_domain: 978e2ad626fSUlf Hansson of_genpd_del_provider(pdev->dev.of_node); 979e2ad626fSUlf Hansson pm_genpd_remove(&prm->prmd->pd); 980e2ad626fSUlf Hansson 981e2ad626fSUlf Hansson return ret; 982e2ad626fSUlf Hansson } 983e2ad626fSUlf Hansson 984e2ad626fSUlf Hansson static struct platform_driver omap_prm_driver = { 985e2ad626fSUlf Hansson .probe = omap_prm_probe, 986e2ad626fSUlf Hansson .driver = { 987e2ad626fSUlf Hansson .name = KBUILD_MODNAME, 988e2ad626fSUlf Hansson .of_match_table = omap_prm_id_table, 989e2ad626fSUlf Hansson }, 990e2ad626fSUlf Hansson }; 991e2ad626fSUlf Hansson builtin_platform_driver(omap_prm_driver); 992