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