0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
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
0034
0035
0036
0037
0038
0039
0040 static struct clk_hw_omap *dpll_core_ck;
0041
0042
0043
0044
0045
0046
0047
0048
0049
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
0072
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) {
0081 high = curr_prcm_set->dpll_speed * 2;
0082 low = curr_prcm_set->dpll_speed;
0083 } else {
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
0158 tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS;
0159
0160 if (rate == curr_prcm_set->xtal_speed)
0161 bypass = 1;
0162
0163
0164 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
0165
0166
0167 omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
0168 bypass);
0169
0170
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
0180
0181
0182
0183
0184
0185
0186
0187
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 }