Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * DPLL + CORE_CLK composite clock functions
0004  *
0005  * Copyright (C) 2005-2008 Texas Instruments, Inc.
0006  * Copyright (C) 2004-2010 Nokia Corporation
0007  *
0008  * Contacts:
0009  * Richard Woodruff <r-woodruff2@ti.com>
0010  * Paul Walmsley
0011  *
0012  * Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
0013  * Gordon McNutt and RidgeRun, Inc.
0014  *
0015  * XXX The DPLL and CORE clocks should be split into two separate clock
0016  * types.
0017  */
0018 #undef DEBUG
0019 
0020 #include <linux/kernel.h>
0021 #include <linux/errno.h>
0022 #include <linux/clk.h>
0023 #include <linux/io.h>
0024 
0025 #include "clock.h"
0026 #include "clock2xxx.h"
0027 #include "opp2xxx.h"
0028 #include "cm2xxx.h"
0029 #include "cm-regbits-24xx.h"
0030 #include "sdrc.h"
0031 #include "sram.h"
0032 
0033 /* #define DOWN_VARIABLE_DPLL 1 */      /* Experimental */
0034 
0035 /*
0036  * dpll_core_ck: pointer to the combined dpll_ck + core_ck on OMAP2xxx
0037  * (currently defined as "dpll_ck" in the OMAP2xxx clock tree).  Set
0038  * during dpll_ck init and used later by omap2xxx_clk_get_core_rate().
0039  */
0040 static struct clk_hw_omap *dpll_core_ck;
0041 
0042 /**
0043  * omap2xxx_clk_get_core_rate - return the CORE_CLK rate
0044  *
0045  * Returns the CORE_CLK rate.  CORE_CLK can have one of three rate
0046  * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
0047  * (the latter is unusual).  This currently should be called with
0048  * struct clk *dpll_ck, which is a composite clock of dpll_ck and
0049  * core_ck.
0050  */
0051 unsigned long omap2xxx_clk_get_core_rate(void)
0052 {
0053     long long core_clk;
0054     u32 v;
0055 
0056     WARN_ON(!dpll_core_ck);
0057 
0058     core_clk = omap2_get_dpll_rate(dpll_core_ck);
0059 
0060     v = omap2xxx_cm_get_core_clk_src();
0061 
0062     if (v == CORE_CLK_SRC_32K)
0063         core_clk = 32768;
0064     else
0065         core_clk *= v;
0066 
0067     return core_clk;
0068 }
0069 
0070 /*
0071  * Uses the current prcm set to tell if a rate is valid.
0072  * You can go slower, but not faster within a given rate set.
0073  */
0074 static long omap2_dpllcore_round_rate(unsigned long target_rate)
0075 {
0076     u32 high, low, core_clk_src;
0077 
0078     core_clk_src = omap2xxx_cm_get_core_clk_src();
0079 
0080     if (core_clk_src == CORE_CLK_SRC_DPLL) {    /* DPLL clockout */
0081         high = curr_prcm_set->dpll_speed * 2;
0082         low = curr_prcm_set->dpll_speed;
0083     } else {                /* DPLL clockout x 2 */
0084         high = curr_prcm_set->dpll_speed;
0085         low = curr_prcm_set->dpll_speed / 2;
0086     }
0087 
0088 #ifdef DOWN_VARIABLE_DPLL
0089     if (target_rate > high)
0090         return high;
0091     else
0092         return target_rate;
0093 #else
0094     if (target_rate > low)
0095         return high;
0096     else
0097         return low;
0098 #endif
0099 
0100 }
0101 
0102 unsigned long omap2_dpllcore_recalc(struct clk_hw *hw,
0103                     unsigned long parent_rate)
0104 {
0105     return omap2xxx_clk_get_core_rate();
0106 }
0107 
0108 int omap2_reprogram_dpllcore(struct clk_hw *hw, unsigned long rate,
0109                  unsigned long parent_rate)
0110 {
0111     struct clk_hw_omap *clk = to_clk_hw_omap(hw);
0112     u32 cur_rate, low, mult, div, valid_rate, done_rate;
0113     u32 bypass = 0;
0114     struct prcm_config tmpset;
0115     const struct dpll_data *dd;
0116 
0117     cur_rate = omap2xxx_clk_get_core_rate();
0118     mult = omap2xxx_cm_get_core_clk_src();
0119 
0120     if ((rate == (cur_rate / 2)) && (mult == 2)) {
0121         omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
0122     } else if ((rate == (cur_rate * 2)) && (mult == 1)) {
0123         omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
0124     } else if (rate != cur_rate) {
0125         valid_rate = omap2_dpllcore_round_rate(rate);
0126         if (valid_rate != rate)
0127             return -EINVAL;
0128 
0129         if (mult == 1)
0130             low = curr_prcm_set->dpll_speed;
0131         else
0132             low = curr_prcm_set->dpll_speed / 2;
0133 
0134         dd = clk->dpll_data;
0135         if (!dd)
0136             return -EINVAL;
0137 
0138         tmpset.cm_clksel1_pll =
0139             omap_clk_ll_ops.clk_readl(&dd->mult_div1_reg);
0140         tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
0141                        dd->div1_mask);
0142         div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
0143         tmpset.cm_clksel2_pll = omap2xxx_cm_get_core_pll_config();
0144         tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK;
0145         if (rate > low) {
0146             tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2;
0147             mult = ((rate / 2) / 1000000);
0148             done_rate = CORE_CLK_SRC_DPLL_X2;
0149         } else {
0150             tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL;
0151             mult = (rate / 1000000);
0152             done_rate = CORE_CLK_SRC_DPLL;
0153         }
0154         tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask));
0155         tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask));
0156 
0157         /* Worst case */
0158         tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS;
0159 
0160         if (rate == curr_prcm_set->xtal_speed)  /* If asking for 1-1 */
0161             bypass = 1;
0162 
0163         /* For omap2xxx_sdrc_init_params() */
0164         omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
0165 
0166         /* Force dll lock mode */
0167         omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
0168                    bypass);
0169 
0170         /* Errata: ret dll entry state */
0171         omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
0172         omap2xxx_sdrc_reprogram(done_rate, 0);
0173     }
0174 
0175     return 0;
0176 }
0177 
0178 /**
0179  * omap2xxx_clkt_dpllcore_init - clk init function for dpll_ck
0180  * @clk: struct clk *dpll_ck
0181  *
0182  * Store a local copy of @clk in dpll_core_ck so other code can query
0183  * the core rate without having to clk_get(), which can sleep.  Must
0184  * only be called once.  No return value.  XXX If the clock
0185  * registration process is ever changed such that dpll_ck is no longer
0186  * statically defined, this code may need to change to increment some
0187  * kind of use count on dpll_ck.
0188  */
0189 void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw)
0190 {
0191     WARN(dpll_core_ck, "dpll_core_ck already set - should never happen");
0192     dpll_core_ck = to_clk_hw_omap(hw);
0193 }