~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-omap2/clkt2xxx_dpllcore.c

Version: ~ [ linux-5.9 ] ~ [ linux-5.8.14 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.70 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.150 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.200 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.238 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.238 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * DPLL + CORE_CLK composite clock functions
  3  *
  4  * Copyright (C) 2005-2008 Texas Instruments, Inc.
  5  * Copyright (C) 2004-2010 Nokia Corporation
  6  *
  7  * Contacts:
  8  * Richard Woodruff <r-woodruff2@ti.com>
  9  * Paul Walmsley
 10  *
 11  * Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
 12  * Gordon McNutt and RidgeRun, Inc.
 13  *
 14  * This program is free software; you can redistribute it and/or modify
 15  * it under the terms of the GNU General Public License version 2 as
 16  * published by the Free Software Foundation.
 17  *
 18  * XXX The DPLL and CORE clocks should be split into two separate clock
 19  * types.
 20  */
 21 #undef DEBUG
 22 
 23 #include <linux/kernel.h>
 24 #include <linux/errno.h>
 25 #include <linux/clk.h>
 26 #include <linux/io.h>
 27 
 28 #include "clock.h"
 29 #include "clock2xxx.h"
 30 #include "opp2xxx.h"
 31 #include "cm2xxx.h"
 32 #include "cm-regbits-24xx.h"
 33 #include "sdrc.h"
 34 #include "sram.h"
 35 
 36 /* #define DOWN_VARIABLE_DPLL 1 */              /* Experimental */
 37 
 38 /*
 39  * dpll_core_ck: pointer to the combined dpll_ck + core_ck on OMAP2xxx
 40  * (currently defined as "dpll_ck" in the OMAP2xxx clock tree).  Set
 41  * during dpll_ck init and used later by omap2xxx_clk_get_core_rate().
 42  */
 43 static struct clk_hw_omap *dpll_core_ck;
 44 
 45 /**
 46  * omap2xxx_clk_get_core_rate - return the CORE_CLK rate
 47  *
 48  * Returns the CORE_CLK rate.  CORE_CLK can have one of three rate
 49  * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
 50  * (the latter is unusual).  This currently should be called with
 51  * struct clk *dpll_ck, which is a composite clock of dpll_ck and
 52  * core_ck.
 53  */
 54 unsigned long omap2xxx_clk_get_core_rate(void)
 55 {
 56         long long core_clk;
 57         u32 v;
 58 
 59         WARN_ON(!dpll_core_ck);
 60 
 61         core_clk = omap2_get_dpll_rate(dpll_core_ck);
 62 
 63         v = omap2xxx_cm_get_core_clk_src();
 64 
 65         if (v == CORE_CLK_SRC_32K)
 66                 core_clk = 32768;
 67         else
 68                 core_clk *= v;
 69 
 70         return core_clk;
 71 }
 72 
 73 /*
 74  * Uses the current prcm set to tell if a rate is valid.
 75  * You can go slower, but not faster within a given rate set.
 76  */
 77 static long omap2_dpllcore_round_rate(unsigned long target_rate)
 78 {
 79         u32 high, low, core_clk_src;
 80 
 81         core_clk_src = omap2xxx_cm_get_core_clk_src();
 82 
 83         if (core_clk_src == CORE_CLK_SRC_DPLL) {        /* DPLL clockout */
 84                 high = curr_prcm_set->dpll_speed * 2;
 85                 low = curr_prcm_set->dpll_speed;
 86         } else {                                /* DPLL clockout x 2 */
 87                 high = curr_prcm_set->dpll_speed;
 88                 low = curr_prcm_set->dpll_speed / 2;
 89         }
 90 
 91 #ifdef DOWN_VARIABLE_DPLL
 92         if (target_rate > high)
 93                 return high;
 94         else
 95                 return target_rate;
 96 #else
 97         if (target_rate > low)
 98                 return high;
 99         else
100                 return low;
101 #endif
102 
103 }
104 
105 unsigned long omap2_dpllcore_recalc(struct clk_hw *hw,
106                                     unsigned long parent_rate)
107 {
108         return omap2xxx_clk_get_core_rate();
109 }
110 
111 int omap2_reprogram_dpllcore(struct clk_hw *hw, unsigned long rate,
112                              unsigned long parent_rate)
113 {
114         struct clk_hw_omap *clk = to_clk_hw_omap(hw);
115         u32 cur_rate, low, mult, div, valid_rate, done_rate;
116         u32 bypass = 0;
117         struct prcm_config tmpset;
118         const struct dpll_data *dd;
119 
120         cur_rate = omap2xxx_clk_get_core_rate();
121         mult = omap2xxx_cm_get_core_clk_src();
122 
123         if ((rate == (cur_rate / 2)) && (mult == 2)) {
124                 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
125         } else if ((rate == (cur_rate * 2)) && (mult == 1)) {
126                 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
127         } else if (rate != cur_rate) {
128                 valid_rate = omap2_dpllcore_round_rate(rate);
129                 if (valid_rate != rate)
130                         return -EINVAL;
131 
132                 if (mult == 1)
133                         low = curr_prcm_set->dpll_speed;
134                 else
135                         low = curr_prcm_set->dpll_speed / 2;
136 
137                 dd = clk->dpll_data;
138                 if (!dd)
139                         return -EINVAL;
140 
141                 tmpset.cm_clksel1_pll =
142                         omap_clk_ll_ops.clk_readl(&dd->mult_div1_reg);
143                 tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
144                                            dd->div1_mask);
145                 div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
146                 tmpset.cm_clksel2_pll = omap2xxx_cm_get_core_pll_config();
147                 tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK;
148                 if (rate > low) {
149                         tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2;
150                         mult = ((rate / 2) / 1000000);
151                         done_rate = CORE_CLK_SRC_DPLL_X2;
152                 } else {
153                         tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL;
154                         mult = (rate / 1000000);
155                         done_rate = CORE_CLK_SRC_DPLL;
156                 }
157                 tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask));
158                 tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask));
159 
160                 /* Worst case */
161                 tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS;
162 
163                 if (rate == curr_prcm_set->xtal_speed)  /* If asking for 1-1 */
164                         bypass = 1;
165 
166                 /* For omap2xxx_sdrc_init_params() */
167                 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
168 
169                 /* Force dll lock mode */
170                 omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
171                                bypass);
172 
173                 /* Errata: ret dll entry state */
174                 omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
175                 omap2xxx_sdrc_reprogram(done_rate, 0);
176         }
177 
178         return 0;
179 }
180 
181 /**
182  * omap2xxx_clkt_dpllcore_init - clk init function for dpll_ck
183  * @clk: struct clk *dpll_ck
184  *
185  * Store a local copy of @clk in dpll_core_ck so other code can query
186  * the core rate without having to clk_get(), which can sleep.  Must
187  * only be called once.  No return value.  XXX If the clock
188  * registration process is ever changed such that dpll_ck is no longer
189  * statically defined, this code may need to change to increment some
190  * kind of use count on dpll_ck.
191  */
192 void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw)
193 {
194         WARN(dpll_core_ck, "dpll_core_ck already set - should never happen");
195         dpll_core_ck = to_clk_hw_omap(hw);
196 }
197 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp