Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Default clock type
0004  *
0005  * Copyright (C) 2005-2008, 2015 Texas Instruments, Inc.
0006  * Copyright (C) 2004-2010 Nokia Corporation
0007  *
0008  * Contacts:
0009  * Richard Woodruff <r-woodruff2@ti.com>
0010  * Paul Walmsley
0011  * Tero Kristo <t-kristo@ti.com>
0012  */
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/errno.h>
0016 #include <linux/clk-provider.h>
0017 #include <linux/io.h>
0018 #include <linux/clk/ti.h>
0019 #include <linux/delay.h>
0020 
0021 #include "clock.h"
0022 
0023 /*
0024  * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait
0025  * for a module to indicate that it is no longer in idle
0026  */
0027 #define MAX_MODULE_ENABLE_WAIT      100000
0028 
0029 /*
0030  * CM module register offsets, used for calculating the companion
0031  * register addresses.
0032  */
0033 #define CM_FCLKEN           0x0000
0034 #define CM_ICLKEN           0x0010
0035 
0036 /**
0037  * _wait_idlest_generic - wait for a module to leave the idle state
0038  * @clk: module clock to wait for (needed for register offsets)
0039  * @reg: virtual address of module IDLEST register
0040  * @mask: value to mask against to determine if the module is active
0041  * @idlest: idle state indicator (0 or 1) for the clock
0042  * @name: name of the clock (for printk)
0043  *
0044  * Wait for a module to leave idle, where its idle-status register is
0045  * not inside the CM module.  Returns 1 if the module left idle
0046  * promptly, or 0 if the module did not leave idle before the timeout
0047  * elapsed.  XXX Deprecated - should be moved into drivers for the
0048  * individual IP block that the IDLEST register exists in.
0049  */
0050 static int _wait_idlest_generic(struct clk_hw_omap *clk,
0051                 struct clk_omap_reg *reg,
0052                 u32 mask, u8 idlest, const char *name)
0053 {
0054     int i = 0, ena = 0;
0055 
0056     ena = (idlest) ? 0 : mask;
0057 
0058     /* Wait until module enters enabled state */
0059     for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
0060         if ((ti_clk_ll_ops->clk_readl(reg) & mask) == ena)
0061             break;
0062         udelay(1);
0063     }
0064 
0065     if (i < MAX_MODULE_ENABLE_WAIT)
0066         pr_debug("omap clock: module associated with clock %s ready after %d loops\n",
0067              name, i);
0068     else
0069         pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n",
0070                name, MAX_MODULE_ENABLE_WAIT);
0071 
0072     return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0;
0073 }
0074 
0075 /**
0076  * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE
0077  * @clk: struct clk * belonging to the module
0078  *
0079  * If the necessary clocks for the OMAP hardware IP block that
0080  * corresponds to clock @clk are enabled, then wait for the module to
0081  * indicate readiness (i.e., to leave IDLE).  This code does not
0082  * belong in the clock code and will be moved in the medium term to
0083  * module-dependent code.  No return value.
0084  */
0085 static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
0086 {
0087     struct clk_omap_reg companion_reg, idlest_reg;
0088     u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
0089     s16 prcm_mod;
0090     int r;
0091 
0092     /* Not all modules have multiple clocks that their IDLEST depends on */
0093     if (clk->ops->find_companion) {
0094         clk->ops->find_companion(clk, &companion_reg, &other_bit);
0095         if (!(ti_clk_ll_ops->clk_readl(&companion_reg) &
0096               (1 << other_bit)))
0097             return;
0098     }
0099 
0100     clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
0101     r = ti_clk_ll_ops->cm_split_idlest_reg(&idlest_reg, &prcm_mod,
0102                            &idlest_reg_id);
0103     if (r) {
0104         /* IDLEST register not in the CM module */
0105         _wait_idlest_generic(clk, &idlest_reg, (1 << idlest_bit),
0106                      idlest_val, clk_hw_get_name(&clk->hw));
0107     } else {
0108         ti_clk_ll_ops->cm_wait_module_ready(0, prcm_mod, idlest_reg_id,
0109                             idlest_bit);
0110     }
0111 }
0112 
0113 /**
0114  * omap2_clk_dflt_find_companion - find companion clock to @clk
0115  * @clk: struct clk * to find the companion clock of
0116  * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
0117  * @other_bit: u8 ** to return the companion clock bit shift in
0118  *
0119  * Note: We don't need special code here for INVERT_ENABLE for the
0120  * time being since INVERT_ENABLE only applies to clocks enabled by
0121  * CM_CLKEN_PLL
0122  *
0123  * Convert CM_ICLKEN* <-> CM_FCLKEN*.  This conversion assumes it's
0124  * just a matter of XORing the bits.
0125  *
0126  * Some clocks don't have companion clocks.  For example, modules with
0127  * only an interface clock (such as MAILBOXES) don't have a companion
0128  * clock.  Right now, this code relies on the hardware exporting a bit
0129  * in the correct companion register that indicates that the
0130  * nonexistent 'companion clock' is active.  Future patches will
0131  * associate this type of code with per-module data structures to
0132  * avoid this issue, and remove the casts.  No return value.
0133  */
0134 void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
0135                    struct clk_omap_reg *other_reg,
0136                    u8 *other_bit)
0137 {
0138     memcpy(other_reg, &clk->enable_reg, sizeof(*other_reg));
0139 
0140     /*
0141      * Convert CM_ICLKEN* <-> CM_FCLKEN*.  This conversion assumes
0142      * it's just a matter of XORing the bits.
0143      */
0144     other_reg->offset ^= (CM_FCLKEN ^ CM_ICLKEN);
0145 
0146     *other_bit = clk->enable_bit;
0147 }
0148 
0149 /**
0150  * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk
0151  * @clk: struct clk * to find IDLEST info for
0152  * @idlest_reg: void __iomem ** to return the CM_IDLEST va in
0153  * @idlest_bit: u8 * to return the CM_IDLEST bit shift in
0154  * @idlest_val: u8 * to return the idle status indicator
0155  *
0156  * Return the CM_IDLEST register address and bit shift corresponding
0157  * to the module that "owns" this clock.  This default code assumes
0158  * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that
0159  * the IDLEST register address ID corresponds to the CM_*CLKEN
0160  * register address ID (e.g., that CM_FCLKEN2 corresponds to
0161  * CM_IDLEST2).  This is not true for all modules.  No return value.
0162  */
0163 void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
0164                 struct clk_omap_reg *idlest_reg, u8 *idlest_bit,
0165                 u8 *idlest_val)
0166 {
0167     memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg));
0168 
0169     idlest_reg->offset &= ~0xf0;
0170     idlest_reg->offset |= 0x20;
0171 
0172     *idlest_bit = clk->enable_bit;
0173 
0174     /*
0175      * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
0176      * 34xx reverses this, just to keep us on our toes
0177      * AM35xx uses both, depending on the module.
0178      */
0179     *idlest_val = ti_clk_get_features()->cm_idlest_val;
0180 }
0181 
0182 /**
0183  * omap2_dflt_clk_enable - enable a clock in the hardware
0184  * @hw: struct clk_hw * of the clock to enable
0185  *
0186  * Enable the clock @hw in the hardware.  We first call into the OMAP
0187  * clockdomain code to "enable" the corresponding clockdomain if this
0188  * is the first enabled user of the clockdomain.  Then program the
0189  * hardware to enable the clock.  Then wait for the IP block that uses
0190  * this clock to leave idle (if applicable).  Returns the error value
0191  * from clkdm_clk_enable() if it terminated with an error, or -EINVAL
0192  * if @hw has a null clock enable_reg, or zero upon success.
0193  */
0194 int omap2_dflt_clk_enable(struct clk_hw *hw)
0195 {
0196     struct clk_hw_omap *clk;
0197     u32 v;
0198     int ret = 0;
0199     bool clkdm_control;
0200 
0201     if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL)
0202         clkdm_control = false;
0203     else
0204         clkdm_control = true;
0205 
0206     clk = to_clk_hw_omap(hw);
0207 
0208     if (clkdm_control && clk->clkdm) {
0209         ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
0210         if (ret) {
0211             WARN(1,
0212                  "%s: could not enable %s's clockdomain %s: %d\n",
0213                  __func__, clk_hw_get_name(hw),
0214                  clk->clkdm_name, ret);
0215             return ret;
0216         }
0217     }
0218 
0219     /* FIXME should not have INVERT_ENABLE bit here */
0220     v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
0221     if (clk->flags & INVERT_ENABLE)
0222         v &= ~(1 << clk->enable_bit);
0223     else
0224         v |= (1 << clk->enable_bit);
0225     ti_clk_ll_ops->clk_writel(v, &clk->enable_reg);
0226     v = ti_clk_ll_ops->clk_readl(&clk->enable_reg); /* OCP barrier */
0227 
0228     if (clk->ops && clk->ops->find_idlest)
0229         _omap2_module_wait_ready(clk);
0230 
0231     return 0;
0232 }
0233 
0234 /**
0235  * omap2_dflt_clk_disable - disable a clock in the hardware
0236  * @hw: struct clk_hw * of the clock to disable
0237  *
0238  * Disable the clock @hw in the hardware, and call into the OMAP
0239  * clockdomain code to "disable" the corresponding clockdomain if all
0240  * clocks/hwmods in that clockdomain are now disabled.  No return
0241  * value.
0242  */
0243 void omap2_dflt_clk_disable(struct clk_hw *hw)
0244 {
0245     struct clk_hw_omap *clk;
0246     u32 v;
0247 
0248     clk = to_clk_hw_omap(hw);
0249 
0250     v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
0251     if (clk->flags & INVERT_ENABLE)
0252         v |= (1 << clk->enable_bit);
0253     else
0254         v &= ~(1 << clk->enable_bit);
0255     ti_clk_ll_ops->clk_writel(v, &clk->enable_reg);
0256     /* No OCP barrier needed here since it is a disable operation */
0257 
0258     if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) &&
0259         clk->clkdm)
0260         ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
0261 }
0262 
0263 /**
0264  * omap2_dflt_clk_is_enabled - is clock enabled in the hardware?
0265  * @hw: struct clk_hw * to check
0266  *
0267  * Return 1 if the clock represented by @hw is enabled in the
0268  * hardware, or 0 otherwise.  Intended for use in the struct
0269  * clk_ops.is_enabled function pointer.
0270  */
0271 int omap2_dflt_clk_is_enabled(struct clk_hw *hw)
0272 {
0273     struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0274     u32 v;
0275 
0276     v = ti_clk_ll_ops->clk_readl(&clk->enable_reg);
0277 
0278     if (clk->flags & INVERT_ENABLE)
0279         v ^= BIT(clk->enable_bit);
0280 
0281     v &= BIT(clk->enable_bit);
0282 
0283     return v ? 1 : 0;
0284 }
0285 
0286 const struct clk_hw_omap_ops clkhwops_wait = {
0287     .find_idlest    = omap2_clk_dflt_find_idlest,
0288     .find_companion = omap2_clk_dflt_find_companion,
0289 };