0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #undef DEBUG
0025
0026 #include <linux/kernel.h>
0027 #include <linux/errno.h>
0028 #include <linux/clk.h>
0029 #include <linux/io.h>
0030 #include <linux/cpufreq.h>
0031 #include <linux/slab.h>
0032
0033 #include "soc.h"
0034 #include "clock.h"
0035 #include "clock2xxx.h"
0036 #include "opp2xxx.h"
0037 #include "cm2xxx.h"
0038 #include "cm-regbits-24xx.h"
0039 #include "sdrc.h"
0040 #include "sram.h"
0041
0042 const struct prcm_config *curr_prcm_set;
0043 const struct prcm_config *rate_table;
0044
0045
0046
0047
0048
0049
0050 static unsigned long sys_ck_rate;
0051
0052
0053
0054
0055
0056
0057
0058 unsigned long omap2_table_mpu_recalc(struct clk_hw *clk,
0059 unsigned long parent_rate)
0060 {
0061 return curr_prcm_set->mpu_speed;
0062 }
0063
0064
0065
0066
0067
0068
0069
0070
0071 long omap2_round_to_table_rate(struct clk_hw *hw, unsigned long rate,
0072 unsigned long *parent_rate)
0073 {
0074 const struct prcm_config *ptr;
0075 long highest_rate;
0076
0077 highest_rate = -EINVAL;
0078
0079 for (ptr = rate_table; ptr->mpu_speed; ptr++) {
0080 if (!(ptr->flags & cpu_mask))
0081 continue;
0082 if (ptr->xtal_speed != sys_ck_rate)
0083 continue;
0084
0085 highest_rate = ptr->mpu_speed;
0086
0087
0088 if (ptr->mpu_speed <= rate)
0089 break;
0090 }
0091 return highest_rate;
0092 }
0093
0094
0095 int omap2_select_table_rate(struct clk_hw *hw, unsigned long rate,
0096 unsigned long parent_rate)
0097 {
0098 u32 cur_rate, done_rate, bypass = 0;
0099 const struct prcm_config *prcm;
0100 unsigned long found_speed = 0;
0101 unsigned long flags;
0102
0103 for (prcm = rate_table; prcm->mpu_speed; prcm++) {
0104 if (!(prcm->flags & cpu_mask))
0105 continue;
0106
0107 if (prcm->xtal_speed != sys_ck_rate)
0108 continue;
0109
0110 if (prcm->mpu_speed <= rate) {
0111 found_speed = prcm->mpu_speed;
0112 break;
0113 }
0114 }
0115
0116 if (!found_speed) {
0117 printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
0118 rate / 1000000);
0119 return -EINVAL;
0120 }
0121
0122 curr_prcm_set = prcm;
0123 cur_rate = omap2xxx_clk_get_core_rate();
0124
0125 if (prcm->dpll_speed == cur_rate / 2) {
0126 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
0127 } else if (prcm->dpll_speed == cur_rate * 2) {
0128 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
0129 } else if (prcm->dpll_speed != cur_rate) {
0130 local_irq_save(flags);
0131
0132 if (prcm->dpll_speed == prcm->xtal_speed)
0133 bypass = 1;
0134
0135 if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) ==
0136 CORE_CLK_SRC_DPLL_X2)
0137 done_rate = CORE_CLK_SRC_DPLL_X2;
0138 else
0139 done_rate = CORE_CLK_SRC_DPLL;
0140
0141 omap2xxx_cm_set_mod_dividers(prcm->cm_clksel_mpu,
0142 prcm->cm_clksel_dsp,
0143 prcm->cm_clksel_gfx,
0144 prcm->cm_clksel1_core,
0145 prcm->cm_clksel_mdm);
0146
0147
0148 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
0149
0150 omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
0151 bypass);
0152
0153 omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
0154 omap2xxx_sdrc_reprogram(done_rate, 0);
0155
0156 local_irq_restore(flags);
0157 }
0158
0159 return 0;
0160 }
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170 void omap2xxx_clkt_vps_check_bootloader_rates(void)
0171 {
0172 const struct prcm_config *prcm = NULL;
0173 unsigned long rate;
0174
0175 rate = omap2xxx_clk_get_core_rate();
0176 for (prcm = rate_table; prcm->mpu_speed; prcm++) {
0177 if (!(prcm->flags & cpu_mask))
0178 continue;
0179 if (prcm->xtal_speed != sys_ck_rate)
0180 continue;
0181 if (prcm->dpll_speed <= rate)
0182 break;
0183 }
0184 curr_prcm_set = prcm;
0185 }
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196 void omap2xxx_clkt_vps_late_init(void)
0197 {
0198 struct clk *c;
0199
0200 c = clk_get(NULL, "sys_ck");
0201 if (IS_ERR(c)) {
0202 WARN(1, "could not locate sys_ck\n");
0203 } else {
0204 sys_ck_rate = clk_get_rate(c);
0205 clk_put(c);
0206 }
0207 }
0208
0209 #ifdef CONFIG_OF
0210 #include <linux/clk-provider.h>
0211 #include <linux/clkdev.h>
0212
0213 static const struct clk_ops virt_prcm_set_ops = {
0214 .recalc_rate = &omap2_table_mpu_recalc,
0215 .set_rate = &omap2_select_table_rate,
0216 .round_rate = &omap2_round_to_table_rate,
0217 };
0218
0219
0220
0221
0222
0223
0224
0225
0226 void omap2xxx_clkt_vps_init(void)
0227 {
0228 struct clk_init_data init = { NULL };
0229 struct clk_hw_omap *hw = NULL;
0230 struct clk *clk;
0231 const char *parent_name = "mpu_ck";
0232
0233 omap2xxx_clkt_vps_late_init();
0234 omap2xxx_clkt_vps_check_bootloader_rates();
0235
0236 hw = kzalloc(sizeof(*hw), GFP_KERNEL);
0237 if (!hw)
0238 return;
0239 init.name = "virt_prcm_set";
0240 init.ops = &virt_prcm_set_ops;
0241 init.parent_names = &parent_name;
0242 init.num_parents = 1;
0243
0244 hw->hw.init = &init;
0245
0246 clk = clk_register(NULL, &hw->hw);
0247 if (IS_ERR(clk)) {
0248 printk(KERN_ERR "Failed to register clock\n");
0249 kfree(hw);
0250 return;
0251 }
0252
0253 clkdev_create(clk, "cpufreq_ck", NULL);
0254 }
0255 #endif