1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#undef DEBUG
28
29#include <linux/kernel.h>
30#include <linux/errno.h>
31#include <linux/clk.h>
32#include <linux/io.h>
33#include <linux/cpufreq.h>
34#include <linux/slab.h>
35
36#include "soc.h"
37#include "clock.h"
38#include "clock2xxx.h"
39#include "opp2xxx.h"
40#include "cm2xxx.h"
41#include "cm-regbits-24xx.h"
42#include "sdrc.h"
43#include "sram.h"
44
45const struct prcm_config *curr_prcm_set;
46const struct prcm_config *rate_table;
47
48
49
50
51
52
53static unsigned long sys_ck_rate;
54
55
56
57
58
59
60
61unsigned long omap2_table_mpu_recalc(struct clk_hw *clk,
62 unsigned long parent_rate)
63{
64 return curr_prcm_set->mpu_speed;
65}
66
67
68
69
70
71
72
73
74long omap2_round_to_table_rate(struct clk_hw *hw, unsigned long rate,
75 unsigned long *parent_rate)
76{
77 const struct prcm_config *ptr;
78 long highest_rate;
79
80 highest_rate = -EINVAL;
81
82 for (ptr = rate_table; ptr->mpu_speed; ptr++) {
83 if (!(ptr->flags & cpu_mask))
84 continue;
85 if (ptr->xtal_speed != sys_ck_rate)
86 continue;
87
88 highest_rate = ptr->mpu_speed;
89
90
91 if (ptr->mpu_speed <= rate)
92 break;
93 }
94 return highest_rate;
95}
96
97
98int omap2_select_table_rate(struct clk_hw *hw, unsigned long rate,
99 unsigned long parent_rate)
100{
101 u32 cur_rate, done_rate, bypass = 0;
102 const struct prcm_config *prcm;
103 unsigned long found_speed = 0;
104 unsigned long flags;
105
106 for (prcm = rate_table; prcm->mpu_speed; prcm++) {
107 if (!(prcm->flags & cpu_mask))
108 continue;
109
110 if (prcm->xtal_speed != sys_ck_rate)
111 continue;
112
113 if (prcm->mpu_speed <= rate) {
114 found_speed = prcm->mpu_speed;
115 break;
116 }
117 }
118
119 if (!found_speed) {
120 printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
121 rate / 1000000);
122 return -EINVAL;
123 }
124
125 curr_prcm_set = prcm;
126 cur_rate = omap2xxx_clk_get_core_rate();
127
128 if (prcm->dpll_speed == cur_rate / 2) {
129 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
130 } else if (prcm->dpll_speed == cur_rate * 2) {
131 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
132 } else if (prcm->dpll_speed != cur_rate) {
133 local_irq_save(flags);
134
135 if (prcm->dpll_speed == prcm->xtal_speed)
136 bypass = 1;
137
138 if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) ==
139 CORE_CLK_SRC_DPLL_X2)
140 done_rate = CORE_CLK_SRC_DPLL_X2;
141 else
142 done_rate = CORE_CLK_SRC_DPLL;
143
144 omap2xxx_cm_set_mod_dividers(prcm->cm_clksel_mpu,
145 prcm->cm_clksel_dsp,
146 prcm->cm_clksel_gfx,
147 prcm->cm_clksel1_core,
148 prcm->cm_clksel_mdm);
149
150
151 omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
152
153 omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
154 bypass);
155
156 omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
157 omap2xxx_sdrc_reprogram(done_rate, 0);
158
159 local_irq_restore(flags);
160 }
161
162 return 0;
163}
164
165
166
167
168
169
170
171
172
173void omap2xxx_clkt_vps_check_bootloader_rates(void)
174{
175 const struct prcm_config *prcm = NULL;
176 unsigned long rate;
177
178 rate = omap2xxx_clk_get_core_rate();
179 for (prcm = rate_table; prcm->mpu_speed; prcm++) {
180 if (!(prcm->flags & cpu_mask))
181 continue;
182 if (prcm->xtal_speed != sys_ck_rate)
183 continue;
184 if (prcm->dpll_speed <= rate)
185 break;
186 }
187 curr_prcm_set = prcm;
188}
189
190
191
192
193
194
195
196
197
198
199void omap2xxx_clkt_vps_late_init(void)
200{
201 struct clk *c;
202
203 c = clk_get(NULL, "sys_ck");
204 if (IS_ERR(c)) {
205 WARN(1, "could not locate sys_ck\n");
206 } else {
207 sys_ck_rate = clk_get_rate(c);
208 clk_put(c);
209 }
210}
211
212#ifdef CONFIG_OF
213#include <linux/clk-provider.h>
214#include <linux/clkdev.h>
215
216static const struct clk_ops virt_prcm_set_ops = {
217 .recalc_rate = &omap2_table_mpu_recalc,
218 .set_rate = &omap2_select_table_rate,
219 .round_rate = &omap2_round_to_table_rate,
220};
221
222
223
224
225
226
227
228
229void omap2xxx_clkt_vps_init(void)
230{
231 struct clk_init_data init = { NULL };
232 struct clk_hw_omap *hw = NULL;
233 struct clk *clk;
234 const char *parent_name = "mpu_ck";
235
236 omap2xxx_clkt_vps_late_init();
237 omap2xxx_clkt_vps_check_bootloader_rates();
238
239 hw = kzalloc(sizeof(*hw), GFP_KERNEL);
240 if (!hw)
241 goto cleanup;
242 init.name = "virt_prcm_set";
243 init.ops = &virt_prcm_set_ops;
244 init.parent_names = &parent_name;
245 init.num_parents = 1;
246
247 hw->hw.init = &init;
248
249 clk = clk_register(NULL, &hw->hw);
250 clkdev_create(clk, "cpufreq_ck", NULL);
251 return;
252cleanup:
253 kfree(hw);
254}
255#endif
256