Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * AM33XX CM functions
0004  *
0005  * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/
0006  * Vaibhav Hiremath <hvaibhav@ti.com>
0007  *
0008  * Reference taken from from OMAP4 cminst44xx.c
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/types.h>
0013 #include <linux/errno.h>
0014 #include <linux/err.h>
0015 #include <linux/io.h>
0016 
0017 #include "clockdomain.h"
0018 #include "cm.h"
0019 #include "cm33xx.h"
0020 #include "cm-regbits-34xx.h"
0021 #include "cm-regbits-33xx.h"
0022 #include "prm33xx.h"
0023 
0024 /*
0025  * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
0026  *
0027  *   0x0 func:     Module is fully functional, including OCP
0028  *   0x1 trans:    Module is performing transition: wakeup, or sleep, or sleep
0029  *                 abortion
0030  *   0x2 idle:     Module is in Idle mode (only OCP part). It is functional if
0031  *                 using separate functional clock
0032  *   0x3 disabled: Module is disabled and cannot be accessed
0033  *
0034  */
0035 #define CLKCTRL_IDLEST_FUNCTIONAL       0x0
0036 #define CLKCTRL_IDLEST_INTRANSITION     0x1
0037 #define CLKCTRL_IDLEST_INTERFACE_IDLE       0x2
0038 #define CLKCTRL_IDLEST_DISABLED         0x3
0039 
0040 /* Private functions */
0041 
0042 /* Read a register in a CM instance */
0043 static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx)
0044 {
0045     return readl_relaxed(cm_base.va + inst + idx);
0046 }
0047 
0048 /* Write into a register in a CM */
0049 static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx)
0050 {
0051     writel_relaxed(val, cm_base.va + inst + idx);
0052 }
0053 
0054 /* Read-modify-write a register in CM */
0055 static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
0056 {
0057     u32 v;
0058 
0059     v = am33xx_cm_read_reg(inst, idx);
0060     v &= ~mask;
0061     v |= bits;
0062     am33xx_cm_write_reg(v, inst, idx);
0063 
0064     return v;
0065 }
0066 
0067 static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
0068 {
0069     u32 v;
0070 
0071     v = am33xx_cm_read_reg(inst, idx);
0072     v &= mask;
0073     v >>= __ffs(mask);
0074 
0075     return v;
0076 }
0077 
0078 /**
0079  * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
0080  * @inst: CM instance register offset (*_INST macro)
0081  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
0082  *
0083  * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
0084  * bit 0.
0085  */
0086 static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
0087 {
0088     u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
0089     v &= AM33XX_IDLEST_MASK;
0090     v >>= AM33XX_IDLEST_SHIFT;
0091     return v;
0092 }
0093 
0094 /**
0095  * _is_module_ready - can module registers be accessed without causing an abort?
0096  * @inst: CM instance register offset (*_INST macro)
0097  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
0098  *
0099  * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
0100  * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
0101  */
0102 static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
0103 {
0104     u32 v;
0105 
0106     v = _clkctrl_idlest(inst, clkctrl_offs);
0107 
0108     return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
0109         v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
0110 }
0111 
0112 /**
0113  * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
0114  * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
0115  * @inst: CM instance register offset (*_INST macro)
0116  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
0117  *
0118  * @c must be the unshifted value for CLKTRCTRL - i.e., this function
0119  * will handle the shift itself.
0120  */
0121 static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
0122 {
0123     u32 v;
0124 
0125     v = am33xx_cm_read_reg(inst, cdoffs);
0126     v &= ~AM33XX_CLKTRCTRL_MASK;
0127     v |= c << AM33XX_CLKTRCTRL_SHIFT;
0128     am33xx_cm_write_reg(v, inst, cdoffs);
0129 }
0130 
0131 /* Public functions */
0132 
0133 /**
0134  * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
0135  * @inst: CM instance register offset (*_INST macro)
0136  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
0137  *
0138  * Returns true if the clockdomain referred to by (@inst, @cdoffs)
0139  * is in hardware-supervised idle mode, or 0 otherwise.
0140  */
0141 static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
0142 {
0143     u32 v;
0144 
0145     v = am33xx_cm_read_reg(inst, cdoffs);
0146     v &= AM33XX_CLKTRCTRL_MASK;
0147     v >>= AM33XX_CLKTRCTRL_SHIFT;
0148 
0149     return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
0150 }
0151 
0152 /**
0153  * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
0154  * @inst: CM instance register offset (*_INST macro)
0155  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
0156  *
0157  * Put a clockdomain referred to by (@inst, @cdoffs) into
0158  * hardware-supervised idle mode.  No return value.
0159  */
0160 static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
0161 {
0162     _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
0163 }
0164 
0165 /**
0166  * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
0167  * @inst: CM instance register offset (*_INST macro)
0168  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
0169  *
0170  * Put a clockdomain referred to by (@inst, @cdoffs) into
0171  * software-supervised idle mode, i.e., controlled manually by the
0172  * Linux OMAP clockdomain code.  No return value.
0173  */
0174 static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
0175 {
0176     _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
0177 }
0178 
0179 /**
0180  * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle
0181  * @inst: CM instance register offset (*_INST macro)
0182  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
0183  *
0184  * Put a clockdomain referred to by (@inst, @cdoffs) into idle
0185  * No return value.
0186  */
0187 static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
0188 {
0189     _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
0190 }
0191 
0192 /**
0193  * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle
0194  * @inst: CM instance register offset (*_INST macro)
0195  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
0196  *
0197  * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
0198  * waking it up.  No return value.
0199  */
0200 static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
0201 {
0202     _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
0203 }
0204 
0205 /*
0206  *
0207  */
0208 
0209 /**
0210  * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
0211  * @part: PRCM partition, ignored for AM33xx
0212  * @inst: CM instance register offset (*_INST macro)
0213  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
0214  * @bit_shift: bit shift for the register, ignored for AM33xx
0215  *
0216  * Wait for the module IDLEST to be functional. If the idle state is in any
0217  * the non functional state (trans, idle or disabled), module and thus the
0218  * sysconfig cannot be accessed and will probably lead to an "imprecise
0219  * external abort"
0220  */
0221 static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
0222                        u8 bit_shift)
0223 {
0224     int i = 0;
0225 
0226     omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
0227               MAX_MODULE_READY_TIME, i);
0228 
0229     return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
0230 }
0231 
0232 /**
0233  * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
0234  * state
0235  * @part: CM partition, ignored for AM33xx
0236  * @inst: CM instance register offset (*_INST macro)
0237  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
0238  * @bit_shift: bit shift for the register, ignored for AM33xx
0239  *
0240  * Wait for the module IDLEST to be disabled. Some PRCM transition,
0241  * like reset assertion or parent clock de-activation must wait the
0242  * module to be fully disabled.
0243  */
0244 static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
0245                       u8 bit_shift)
0246 {
0247     int i = 0;
0248 
0249     omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
0250                 CLKCTRL_IDLEST_DISABLED),
0251                 MAX_MODULE_READY_TIME, i);
0252 
0253     return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
0254 }
0255 
0256 /**
0257  * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
0258  * @mode: Module mode (SW or HW)
0259  * @part: CM partition, ignored for AM33xx
0260  * @inst: CM instance register offset (*_INST macro)
0261  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
0262  *
0263  * No return value.
0264  */
0265 static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
0266                     u16 clkctrl_offs)
0267 {
0268     u32 v;
0269 
0270     v = am33xx_cm_read_reg(inst, clkctrl_offs);
0271     v &= ~AM33XX_MODULEMODE_MASK;
0272     v |= mode << AM33XX_MODULEMODE_SHIFT;
0273     am33xx_cm_write_reg(v, inst, clkctrl_offs);
0274 }
0275 
0276 /**
0277  * am33xx_cm_module_disable - Disable the module inside CLKCTRL
0278  * @part: CM partition, ignored for AM33xx
0279  * @inst: CM instance register offset (*_INST macro)
0280  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
0281  *
0282  * No return value.
0283  */
0284 static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
0285 {
0286     u32 v;
0287 
0288     v = am33xx_cm_read_reg(inst, clkctrl_offs);
0289     v &= ~AM33XX_MODULEMODE_MASK;
0290     am33xx_cm_write_reg(v, inst, clkctrl_offs);
0291 }
0292 
0293 /*
0294  * Clockdomain low-level functions
0295  */
0296 
0297 static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
0298 {
0299     am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
0300     return 0;
0301 }
0302 
0303 static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
0304 {
0305     am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
0306     return 0;
0307 }
0308 
0309 static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
0310 {
0311     am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
0312 }
0313 
0314 static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
0315 {
0316     am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
0317 }
0318 
0319 static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
0320 {
0321     if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
0322         return am33xx_clkdm_wakeup(clkdm);
0323 
0324     return 0;
0325 }
0326 
0327 static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
0328 {
0329     bool hwsup = false;
0330 
0331     hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
0332 
0333     if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
0334         am33xx_clkdm_sleep(clkdm);
0335 
0336     return 0;
0337 }
0338 
0339 static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset)
0340 {
0341     return cm_base.pa + inst + offset;
0342 }
0343 
0344 /**
0345  * am33xx_clkdm_save_context - Save the clockdomain transition context
0346  * @clkdm: The clockdomain pointer whose context needs to be saved
0347  *
0348  * Save the clockdomain transition context.
0349  */
0350 static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
0351 {
0352     clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst,
0353                          clkdm->clkdm_offs,
0354                          AM33XX_CLKTRCTRL_MASK);
0355 
0356     return 0;
0357 }
0358 
0359 /**
0360  * am33xx_restore_save_context - Restore the clockdomain transition context
0361  * @clkdm: The clockdomain pointer whose context needs to be restored
0362  *
0363  * Restore the clockdomain transition context.
0364  */
0365 static int am33xx_clkdm_restore_context(struct clockdomain *clkdm)
0366 {
0367     switch (clkdm->context) {
0368     case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
0369         am33xx_clkdm_deny_idle(clkdm);
0370         break;
0371     case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
0372         am33xx_clkdm_sleep(clkdm);
0373         break;
0374     case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
0375         am33xx_clkdm_wakeup(clkdm);
0376         break;
0377     case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
0378         am33xx_clkdm_allow_idle(clkdm);
0379         break;
0380     }
0381     return 0;
0382 }
0383 
0384 struct clkdm_ops am33xx_clkdm_operations = {
0385     .clkdm_sleep        = am33xx_clkdm_sleep,
0386     .clkdm_wakeup       = am33xx_clkdm_wakeup,
0387     .clkdm_allow_idle   = am33xx_clkdm_allow_idle,
0388     .clkdm_deny_idle    = am33xx_clkdm_deny_idle,
0389     .clkdm_clk_enable   = am33xx_clkdm_clk_enable,
0390     .clkdm_clk_disable  = am33xx_clkdm_clk_disable,
0391     .clkdm_save_context = am33xx_clkdm_save_context,
0392     .clkdm_restore_context  = am33xx_clkdm_restore_context,
0393 };
0394 
0395 static const struct cm_ll_data am33xx_cm_ll_data = {
0396     .wait_module_ready  = &am33xx_cm_wait_module_ready,
0397     .wait_module_idle   = &am33xx_cm_wait_module_idle,
0398     .module_enable      = &am33xx_cm_module_enable,
0399     .module_disable     = &am33xx_cm_module_disable,
0400     .xlate_clkctrl      = &am33xx_cm_xlate_clkctrl,
0401 };
0402 
0403 int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
0404 {
0405     return cm_register(&am33xx_cm_ll_data);
0406 }
0407 
0408 static void __exit am33xx_cm_exit(void)
0409 {
0410     cm_unregister(&am33xx_cm_ll_data);
0411 }
0412 __exitcall(am33xx_cm_exit);