root/arch/arm/mach-omap2/cm33xx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. am33xx_cm_read_reg
  2. am33xx_cm_write_reg
  3. am33xx_cm_rmw_reg_bits
  4. am33xx_cm_read_reg_bits
  5. _clkctrl_idlest
  6. _is_module_ready
  7. _clktrctrl_write
  8. am33xx_cm_is_clkdm_in_hwsup
  9. am33xx_cm_clkdm_enable_hwsup
  10. am33xx_cm_clkdm_disable_hwsup
  11. am33xx_cm_clkdm_force_sleep
  12. am33xx_cm_clkdm_force_wakeup
  13. am33xx_cm_wait_module_ready
  14. am33xx_cm_wait_module_idle
  15. am33xx_cm_module_enable
  16. am33xx_cm_module_disable
  17. am33xx_clkdm_sleep
  18. am33xx_clkdm_wakeup
  19. am33xx_clkdm_allow_idle
  20. am33xx_clkdm_deny_idle
  21. am33xx_clkdm_clk_enable
  22. am33xx_clkdm_clk_disable
  23. am33xx_cm_xlate_clkctrl
  24. am33xx_clkdm_save_context
  25. am33xx_clkdm_restore_context
  26. am33xx_cm_init
  27. am33xx_cm_exit

   1 /*
   2  * AM33XX CM functions
   3  *
   4  * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
   5  * Vaibhav Hiremath <hvaibhav@ti.com>
   6  *
   7  * Reference taken from from OMAP4 cminst44xx.c
   8  *
   9  * This program is free software; you can redistribute it and/or
  10  * modify it under the terms of the GNU General Public License as
  11  * published by the Free Software Foundation version 2.
  12  *
  13  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  14  * kind, whether express or implied; without even the implied warranty
  15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16  * GNU General Public License for more details.
  17  */
  18 
  19 #include <linux/kernel.h>
  20 #include <linux/types.h>
  21 #include <linux/errno.h>
  22 #include <linux/err.h>
  23 #include <linux/io.h>
  24 
  25 #include "clockdomain.h"
  26 #include "cm.h"
  27 #include "cm33xx.h"
  28 #include "cm-regbits-34xx.h"
  29 #include "cm-regbits-33xx.h"
  30 #include "prm33xx.h"
  31 
  32 /*
  33  * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
  34  *
  35  *   0x0 func:     Module is fully functional, including OCP
  36  *   0x1 trans:    Module is performing transition: wakeup, or sleep, or sleep
  37  *                 abortion
  38  *   0x2 idle:     Module is in Idle mode (only OCP part). It is functional if
  39  *                 using separate functional clock
  40  *   0x3 disabled: Module is disabled and cannot be accessed
  41  *
  42  */
  43 #define CLKCTRL_IDLEST_FUNCTIONAL               0x0
  44 #define CLKCTRL_IDLEST_INTRANSITION             0x1
  45 #define CLKCTRL_IDLEST_INTERFACE_IDLE           0x2
  46 #define CLKCTRL_IDLEST_DISABLED                 0x3
  47 
  48 /* Private functions */
  49 
  50 /* Read a register in a CM instance */
  51 static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx)
  52 {
  53         return readl_relaxed(cm_base.va + inst + idx);
  54 }
  55 
  56 /* Write into a register in a CM */
  57 static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx)
  58 {
  59         writel_relaxed(val, cm_base.va + inst + idx);
  60 }
  61 
  62 /* Read-modify-write a register in CM */
  63 static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
  64 {
  65         u32 v;
  66 
  67         v = am33xx_cm_read_reg(inst, idx);
  68         v &= ~mask;
  69         v |= bits;
  70         am33xx_cm_write_reg(v, inst, idx);
  71 
  72         return v;
  73 }
  74 
  75 static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
  76 {
  77         u32 v;
  78 
  79         v = am33xx_cm_read_reg(inst, idx);
  80         v &= mask;
  81         v >>= __ffs(mask);
  82 
  83         return v;
  84 }
  85 
  86 /**
  87  * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
  88  * @inst: CM instance register offset (*_INST macro)
  89  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  90  *
  91  * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
  92  * bit 0.
  93  */
  94 static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
  95 {
  96         u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
  97         v &= AM33XX_IDLEST_MASK;
  98         v >>= AM33XX_IDLEST_SHIFT;
  99         return v;
 100 }
 101 
 102 /**
 103  * _is_module_ready - can module registers be accessed without causing an abort?
 104  * @inst: CM instance register offset (*_INST macro)
 105  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 106  *
 107  * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
 108  * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
 109  */
 110 static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
 111 {
 112         u32 v;
 113 
 114         v = _clkctrl_idlest(inst, clkctrl_offs);
 115 
 116         return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
 117                 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
 118 }
 119 
 120 /**
 121  * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
 122  * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
 123  * @inst: CM instance register offset (*_INST macro)
 124  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 125  *
 126  * @c must be the unshifted value for CLKTRCTRL - i.e., this function
 127  * will handle the shift itself.
 128  */
 129 static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
 130 {
 131         u32 v;
 132 
 133         v = am33xx_cm_read_reg(inst, cdoffs);
 134         v &= ~AM33XX_CLKTRCTRL_MASK;
 135         v |= c << AM33XX_CLKTRCTRL_SHIFT;
 136         am33xx_cm_write_reg(v, inst, cdoffs);
 137 }
 138 
 139 /* Public functions */
 140 
 141 /**
 142  * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
 143  * @inst: CM instance register offset (*_INST macro)
 144  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 145  *
 146  * Returns true if the clockdomain referred to by (@inst, @cdoffs)
 147  * is in hardware-supervised idle mode, or 0 otherwise.
 148  */
 149 static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
 150 {
 151         u32 v;
 152 
 153         v = am33xx_cm_read_reg(inst, cdoffs);
 154         v &= AM33XX_CLKTRCTRL_MASK;
 155         v >>= AM33XX_CLKTRCTRL_SHIFT;
 156 
 157         return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
 158 }
 159 
 160 /**
 161  * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
 162  * @inst: CM instance register offset (*_INST macro)
 163  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 164  *
 165  * Put a clockdomain referred to by (@inst, @cdoffs) into
 166  * hardware-supervised idle mode.  No return value.
 167  */
 168 static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
 169 {
 170         _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
 171 }
 172 
 173 /**
 174  * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
 175  * @inst: CM instance register offset (*_INST macro)
 176  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 177  *
 178  * Put a clockdomain referred to by (@inst, @cdoffs) into
 179  * software-supervised idle mode, i.e., controlled manually by the
 180  * Linux OMAP clockdomain code.  No return value.
 181  */
 182 static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
 183 {
 184         _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
 185 }
 186 
 187 /**
 188  * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle
 189  * @inst: CM instance register offset (*_INST macro)
 190  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 191  *
 192  * Put a clockdomain referred to by (@inst, @cdoffs) into idle
 193  * No return value.
 194  */
 195 static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
 196 {
 197         _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
 198 }
 199 
 200 /**
 201  * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle
 202  * @inst: CM instance register offset (*_INST macro)
 203  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 204  *
 205  * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
 206  * waking it up.  No return value.
 207  */
 208 static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
 209 {
 210         _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
 211 }
 212 
 213 /*
 214  *
 215  */
 216 
 217 /**
 218  * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
 219  * @part: PRCM partition, ignored for AM33xx
 220  * @inst: CM instance register offset (*_INST macro)
 221  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 222  * @bit_shift: bit shift for the register, ignored for AM33xx
 223  *
 224  * Wait for the module IDLEST to be functional. If the idle state is in any
 225  * the non functional state (trans, idle or disabled), module and thus the
 226  * sysconfig cannot be accessed and will probably lead to an "imprecise
 227  * external abort"
 228  */
 229 static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
 230                                        u8 bit_shift)
 231 {
 232         int i = 0;
 233 
 234         omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
 235                           MAX_MODULE_READY_TIME, i);
 236 
 237         return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
 238 }
 239 
 240 /**
 241  * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
 242  * state
 243  * @part: CM partition, ignored for AM33xx
 244  * @inst: CM instance register offset (*_INST macro)
 245  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 246  * @bit_shift: bit shift for the register, ignored for AM33xx
 247  *
 248  * Wait for the module IDLEST to be disabled. Some PRCM transition,
 249  * like reset assertion or parent clock de-activation must wait the
 250  * module to be fully disabled.
 251  */
 252 static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
 253                                       u8 bit_shift)
 254 {
 255         int i = 0;
 256 
 257         omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
 258                                 CLKCTRL_IDLEST_DISABLED),
 259                                 MAX_MODULE_READY_TIME, i);
 260 
 261         return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
 262 }
 263 
 264 /**
 265  * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
 266  * @mode: Module mode (SW or HW)
 267  * @part: CM partition, ignored for AM33xx
 268  * @inst: CM instance register offset (*_INST macro)
 269  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 270  *
 271  * No return value.
 272  */
 273 static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
 274                                     u16 clkctrl_offs)
 275 {
 276         u32 v;
 277 
 278         v = am33xx_cm_read_reg(inst, clkctrl_offs);
 279         v &= ~AM33XX_MODULEMODE_MASK;
 280         v |= mode << AM33XX_MODULEMODE_SHIFT;
 281         am33xx_cm_write_reg(v, inst, clkctrl_offs);
 282 }
 283 
 284 /**
 285  * am33xx_cm_module_disable - Disable the module inside CLKCTRL
 286  * @part: CM partition, ignored for AM33xx
 287  * @inst: CM instance register offset (*_INST macro)
 288  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 289  *
 290  * No return value.
 291  */
 292 static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
 293 {
 294         u32 v;
 295 
 296         v = am33xx_cm_read_reg(inst, clkctrl_offs);
 297         v &= ~AM33XX_MODULEMODE_MASK;
 298         am33xx_cm_write_reg(v, inst, clkctrl_offs);
 299 }
 300 
 301 /*
 302  * Clockdomain low-level functions
 303  */
 304 
 305 static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
 306 {
 307         am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
 308         return 0;
 309 }
 310 
 311 static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
 312 {
 313         am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
 314         return 0;
 315 }
 316 
 317 static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
 318 {
 319         am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
 320 }
 321 
 322 static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
 323 {
 324         am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
 325 }
 326 
 327 static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
 328 {
 329         if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
 330                 return am33xx_clkdm_wakeup(clkdm);
 331 
 332         return 0;
 333 }
 334 
 335 static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
 336 {
 337         bool hwsup = false;
 338 
 339         hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
 340 
 341         if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
 342                 am33xx_clkdm_sleep(clkdm);
 343 
 344         return 0;
 345 }
 346 
 347 static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset)
 348 {
 349         return cm_base.pa + inst + offset;
 350 }
 351 
 352 /**
 353  * am33xx_clkdm_save_context - Save the clockdomain transition context
 354  * @clkdm: The clockdomain pointer whose context needs to be saved
 355  *
 356  * Save the clockdomain transition context.
 357  */
 358 static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
 359 {
 360         clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst,
 361                                                  clkdm->clkdm_offs,
 362                                                  AM33XX_CLKTRCTRL_MASK);
 363 
 364         return 0;
 365 }
 366 
 367 /**
 368  * am33xx_restore_save_context - Restore the clockdomain transition context
 369  * @clkdm: The clockdomain pointer whose context needs to be restored
 370  *
 371  * Restore the clockdomain transition context.
 372  */
 373 static int am33xx_clkdm_restore_context(struct clockdomain *clkdm)
 374 {
 375         switch (clkdm->context) {
 376         case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
 377                 am33xx_clkdm_deny_idle(clkdm);
 378                 break;
 379         case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
 380                 am33xx_clkdm_sleep(clkdm);
 381                 break;
 382         case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
 383                 am33xx_clkdm_wakeup(clkdm);
 384                 break;
 385         case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
 386                 am33xx_clkdm_allow_idle(clkdm);
 387                 break;
 388         }
 389         return 0;
 390 }
 391 
 392 struct clkdm_ops am33xx_clkdm_operations = {
 393         .clkdm_sleep            = am33xx_clkdm_sleep,
 394         .clkdm_wakeup           = am33xx_clkdm_wakeup,
 395         .clkdm_allow_idle       = am33xx_clkdm_allow_idle,
 396         .clkdm_deny_idle        = am33xx_clkdm_deny_idle,
 397         .clkdm_clk_enable       = am33xx_clkdm_clk_enable,
 398         .clkdm_clk_disable      = am33xx_clkdm_clk_disable,
 399         .clkdm_save_context     = am33xx_clkdm_save_context,
 400         .clkdm_restore_context  = am33xx_clkdm_restore_context,
 401 };
 402 
 403 static const struct cm_ll_data am33xx_cm_ll_data = {
 404         .wait_module_ready      = &am33xx_cm_wait_module_ready,
 405         .wait_module_idle       = &am33xx_cm_wait_module_idle,
 406         .module_enable          = &am33xx_cm_module_enable,
 407         .module_disable         = &am33xx_cm_module_disable,
 408         .xlate_clkctrl          = &am33xx_cm_xlate_clkctrl,
 409 };
 410 
 411 int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
 412 {
 413         return cm_register(&am33xx_cm_ll_data);
 414 }
 415 
 416 static void __exit am33xx_cm_exit(void)
 417 {
 418         cm_unregister(&am33xx_cm_ll_data);
 419 }
 420 __exitcall(am33xx_cm_exit);

/* [<][>][^][v][top][bottom][index][help] */