1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * OMAP2xxx CM module functions 4 * 5 * Copyright (C) 2009 Nokia Corporation 6 * Copyright (C) 2008-2010, 2012 Texas Instruments, Inc. 7 * Paul Walmsley 8 * Rajendra Nayak <rnayak@ti.com> 9 */ 10 11 #include <linux/kernel.h> 12 #include <linux/types.h> 13 #include <linux/delay.h> 14 #include <linux/errno.h> 15 #include <linux/err.h> 16 #include <linux/io.h> 17 18 #include "prm2xxx.h" 19 #include "cm.h" 20 #include "cm2xxx.h" 21 #include "cm-regbits-24xx.h" 22 #include "clockdomain.h" 23 24 /* CM_AUTOIDLE_PLL.AUTO_* bit values for DPLLs */ 25 #define DPLL_AUTOIDLE_DISABLE 0x0 26 #define OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP 0x3 27 28 /* CM_AUTOIDLE_PLL.AUTO_* bit values for APLLs (OMAP2xxx only) */ 29 #define OMAP2XXX_APLL_AUTOIDLE_DISABLE 0x0 30 #define OMAP2XXX_APLL_AUTOIDLE_LOW_POWER_STOP 0x3 31 32 /* CM_IDLEST_PLL bit value offset for APLLs (OMAP2xxx only) */ 33 #define EN_APLL_LOCKED 3 34 35 static const u8 omap2xxx_cm_idlest_offs[] = { 36 CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3, OMAP24XX_CM_IDLEST4 37 }; 38 39 /* 40 * 41 */ 42 43 static void _write_clktrctrl(u8 c, s16 module, u32 mask) 44 { 45 u32 v; 46 47 v = omap2_cm_read_mod_reg(module, OMAP2_CM_CLKSTCTRL); 48 v &= ~mask; 49 v |= c << __ffs(mask); 50 omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); 51 } 52 53 static bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) 54 { 55 u32 v; 56 57 v = omap2_cm_read_mod_reg(module, OMAP2_CM_CLKSTCTRL); 58 v &= mask; 59 v >>= __ffs(mask); 60 61 return (v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; 62 } 63 64 static void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) 65 { 66 _write_clktrctrl(OMAP24XX_CLKSTCTRL_ENABLE_AUTO, module, mask); 67 } 68 69 static void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) 70 { 71 _write_clktrctrl(OMAP24XX_CLKSTCTRL_DISABLE_AUTO, module, mask); 72 } 73 74 /* 75 * DPLL autoidle control 76 */ 77 78 static void _omap2xxx_set_dpll_autoidle(u8 m) 79 { 80 u32 v; 81 82 v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); 83 v &= ~OMAP24XX_AUTO_DPLL_MASK; 84 v |= m << OMAP24XX_AUTO_DPLL_SHIFT; 85 omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE); 86 } 87 88 void omap2xxx_cm_set_dpll_disable_autoidle(void) 89 { 90 _omap2xxx_set_dpll_autoidle(OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP); 91 } 92 93 void omap2xxx_cm_set_dpll_auto_low_power_stop(void) 94 { 95 _omap2xxx_set_dpll_autoidle(DPLL_AUTOIDLE_DISABLE); 96 } 97 98 /* 99 * APLL control 100 */ 101 102 static void _omap2xxx_set_apll_autoidle(u8 m, u32 mask) 103 { 104 u32 v; 105 106 v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE); 107 v &= ~mask; 108 v |= m << __ffs(mask); 109 omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE); 110 } 111 112 void omap2xxx_cm_set_apll54_disable_autoidle(void) 113 { 114 _omap2xxx_set_apll_autoidle(OMAP2XXX_APLL_AUTOIDLE_LOW_POWER_STOP, 115 OMAP24XX_AUTO_54M_MASK); 116 } 117 118 void omap2xxx_cm_set_apll54_auto_low_power_stop(void) 119 { 120 _omap2xxx_set_apll_autoidle(OMAP2XXX_APLL_AUTOIDLE_DISABLE, 121 OMAP24XX_AUTO_54M_MASK); 122 } 123 124 void omap2xxx_cm_set_apll96_disable_autoidle(void) 125 { 126 _omap2xxx_set_apll_autoidle(OMAP2XXX_APLL_AUTOIDLE_LOW_POWER_STOP, 127 OMAP24XX_AUTO_96M_MASK); 128 } 129 130 void omap2xxx_cm_set_apll96_auto_low_power_stop(void) 131 { 132 _omap2xxx_set_apll_autoidle(OMAP2XXX_APLL_AUTOIDLE_DISABLE, 133 OMAP24XX_AUTO_96M_MASK); 134 } 135 136 /* Enable an APLL if off */ 137 static int _omap2xxx_apll_enable(u8 enable_bit, u8 status_bit) 138 { 139 u32 v, m; 140 141 m = EN_APLL_LOCKED << enable_bit; 142 143 v = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN); 144 if (v & m) 145 return 0; /* apll already enabled */ 146 147 v |= m; 148 omap2_cm_write_mod_reg(v, PLL_MOD, CM_CLKEN); 149 150 omap2xxx_cm_wait_module_ready(0, PLL_MOD, 1, status_bit); 151 152 /* 153 * REVISIT: Should we return an error code if 154 * omap2xxx_cm_wait_module_ready() fails? 155 */ 156 return 0; 157 } 158 159 /* Stop APLL */ 160 static void _omap2xxx_apll_disable(u8 enable_bit) 161 { 162 u32 v; 163 164 v = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN); 165 v &= ~(EN_APLL_LOCKED << enable_bit); 166 omap2_cm_write_mod_reg(v, PLL_MOD, CM_CLKEN); 167 } 168 169 /* Enable an APLL if off */ 170 int omap2xxx_cm_apll54_enable(void) 171 { 172 return _omap2xxx_apll_enable(OMAP24XX_EN_54M_PLL_SHIFT, 173 OMAP24XX_ST_54M_APLL_SHIFT); 174 } 175 176 /* Enable an APLL if off */ 177 int omap2xxx_cm_apll96_enable(void) 178 { 179 return _omap2xxx_apll_enable(OMAP24XX_EN_96M_PLL_SHIFT, 180 OMAP24XX_ST_96M_APLL_SHIFT); 181 } 182 183 /* Stop APLL */ 184 void omap2xxx_cm_apll54_disable(void) 185 { 186 _omap2xxx_apll_disable(OMAP24XX_EN_54M_PLL_SHIFT); 187 } 188 189 /* Stop APLL */ 190 void omap2xxx_cm_apll96_disable(void) 191 { 192 _omap2xxx_apll_disable(OMAP24XX_EN_96M_PLL_SHIFT); 193 } 194 195 /** 196 * omap2xxx_cm_split_idlest_reg - split CM_IDLEST reg addr into its components 197 * @idlest_reg: CM_IDLEST* virtual address 198 * @prcm_inst: pointer to an s16 to return the PRCM instance offset 199 * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID 200 * 201 * XXX This function is only needed until absolute register addresses are 202 * removed from the OMAP struct clk records. 203 */ 204 static int omap2xxx_cm_split_idlest_reg(struct clk_omap_reg *idlest_reg, 205 s16 *prcm_inst, 206 u8 *idlest_reg_id) 207 { 208 unsigned long offs; 209 u8 idlest_offs; 210 int i; 211 212 idlest_offs = idlest_reg->offset & 0xff; 213 for (i = 0; i < ARRAY_SIZE(omap2xxx_cm_idlest_offs); i++) { 214 if (idlest_offs == omap2xxx_cm_idlest_offs[i]) { 215 *idlest_reg_id = i + 1; 216 break; 217 } 218 } 219 220 if (i == ARRAY_SIZE(omap2xxx_cm_idlest_offs)) 221 return -EINVAL; 222 223 offs = idlest_reg->offset; 224 offs &= 0xff00; 225 *prcm_inst = offs; 226 227 return 0; 228 } 229 230 /* 231 * 232 */ 233 234 /** 235 * omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby 236 * @part: PRCM partition, ignored for OMAP2 237 * @prcm_mod: PRCM module offset 238 * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) 239 * @idlest_shift: shift of the bit in the CM_IDLEST* register to check 240 * 241 * Wait for the PRCM to indicate that the module identified by 242 * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon 243 * success or -EBUSY if the module doesn't enable in time. 244 */ 245 int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, 246 u8 idlest_shift) 247 { 248 int ena = 0, i = 0; 249 u8 cm_idlest_reg; 250 u32 mask; 251 252 if (!idlest_id || (idlest_id > ARRAY_SIZE(omap2xxx_cm_idlest_offs))) 253 return -EINVAL; 254 255 cm_idlest_reg = omap2xxx_cm_idlest_offs[idlest_id - 1]; 256 257 mask = 1 << idlest_shift; 258 ena = mask; 259 260 omap_test_timeout(((omap2_cm_read_mod_reg(prcm_mod, cm_idlest_reg) & 261 mask) == ena), MAX_MODULE_READY_TIME, i); 262 263 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 264 } 265 266 /* Clockdomain low-level functions */ 267 268 static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm) 269 { 270 omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, 271 clkdm->clktrctrl_mask); 272 } 273 274 static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm) 275 { 276 omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, 277 clkdm->clktrctrl_mask); 278 } 279 280 static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) 281 { 282 bool hwsup = false; 283 284 if (!clkdm->clktrctrl_mask) 285 return 0; 286 287 hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, 288 clkdm->clktrctrl_mask); 289 if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) 290 omap2xxx_clkdm_wakeup(clkdm); 291 292 return 0; 293 } 294 295 static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm) 296 { 297 bool hwsup = false; 298 299 if (!clkdm->clktrctrl_mask) 300 return 0; 301 302 hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, 303 clkdm->clktrctrl_mask); 304 305 if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_SLEEP) 306 omap2xxx_clkdm_sleep(clkdm); 307 308 return 0; 309 } 310 311 struct clkdm_ops omap2_clkdm_operations = { 312 .clkdm_add_wkdep = omap2_clkdm_add_wkdep, 313 .clkdm_del_wkdep = omap2_clkdm_del_wkdep, 314 .clkdm_read_wkdep = omap2_clkdm_read_wkdep, 315 .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps, 316 .clkdm_sleep = omap2xxx_clkdm_sleep, 317 .clkdm_wakeup = omap2xxx_clkdm_wakeup, 318 .clkdm_allow_idle = omap2xxx_clkdm_allow_idle, 319 .clkdm_deny_idle = omap2xxx_clkdm_deny_idle, 320 .clkdm_clk_enable = omap2xxx_clkdm_clk_enable, 321 .clkdm_clk_disable = omap2xxx_clkdm_clk_disable, 322 }; 323 324 int omap2xxx_cm_fclks_active(void) 325 { 326 u32 f1, f2; 327 328 f1 = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); 329 f2 = omap2_cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2); 330 331 return (f1 | f2) ? 1 : 0; 332 } 333 334 int omap2xxx_cm_mpu_retention_allowed(void) 335 { 336 u32 l; 337 338 /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */ 339 l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1); 340 if (l & (OMAP2420_EN_MMC_MASK | OMAP24XX_EN_UART2_MASK | 341 OMAP24XX_EN_UART1_MASK | OMAP24XX_EN_MCSPI2_MASK | 342 OMAP24XX_EN_MCSPI1_MASK | OMAP24XX_EN_DSS1_MASK)) 343 return 0; 344 /* Check for UART3. */ 345 l = omap2_cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2); 346 if (l & OMAP24XX_EN_UART3_MASK) 347 return 0; 348 349 return 1; 350 } 351 352 u32 omap2xxx_cm_get_core_clk_src(void) 353 { 354 u32 v; 355 356 v = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); 357 v &= OMAP24XX_CORE_CLK_SRC_MASK; 358 359 return v; 360 } 361 362 u32 omap2xxx_cm_get_core_pll_config(void) 363 { 364 return omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); 365 } 366 367 void omap2xxx_cm_set_mod_dividers(u32 mpu, u32 dsp, u32 gfx, u32 core, u32 mdm) 368 { 369 u32 tmp; 370 371 omap2_cm_write_mod_reg(mpu, MPU_MOD, CM_CLKSEL); 372 omap2_cm_write_mod_reg(dsp, OMAP24XX_DSP_MOD, CM_CLKSEL); 373 omap2_cm_write_mod_reg(gfx, GFX_MOD, CM_CLKSEL); 374 tmp = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & 375 OMAP24XX_CLKSEL_DSS2_MASK; 376 omap2_cm_write_mod_reg(core | tmp, CORE_MOD, CM_CLKSEL1); 377 if (mdm) 378 omap2_cm_write_mod_reg(mdm, OMAP2430_MDM_MOD, CM_CLKSEL); 379 } 380 381 /* 382 * 383 */ 384 385 static const struct cm_ll_data omap2xxx_cm_ll_data = { 386 .split_idlest_reg = &omap2xxx_cm_split_idlest_reg, 387 .wait_module_ready = &omap2xxx_cm_wait_module_ready, 388 }; 389 390 int __init omap2xxx_cm_init(const struct omap_prcm_init_data *data) 391 { 392 return cm_register(&omap2xxx_cm_ll_data); 393 } 394 395 static void __exit omap2xxx_cm_exit(void) 396 { 397 cm_unregister(&omap2xxx_cm_ll_data); 398 } 399 __exitcall(omap2xxx_cm_exit); 400