cpufreq之实例分析.

本文详细解析了nForce2平台的CPUFreq驱动实现原理。重点介绍了如何通过nforce2_set_fsb设置FSB频率,并阐述了目标频率设定、初始化过程及频率转换等关键步骤。
我们看一个注册cpufreq_register_driver 的例子.先看makefile。只要定义了 CONFIG_X86_CPUFREQ_NFORCE2。就会build 出cpufreq-nforce2.o,我们就以它为例
42 obj-$(CONFIG_X86_CPUFREQ_NFORCE2)       += cpufreq-nforce2.o
果然在init函数中调用cpufreq_register_driver
416 static int __init nforce2_init(void)
417 {
418         /* TODO: do we need to detect the processor? */
419 
420         /* detect chipset */
421         if (nforce2_detect_chipset()) {
422                 pr_info("No nForce2 chipset\n");
423                 return -ENODEV;
424         }
425 
426         return cpufreq_register_driver(&nforce2_driver);
427 }
我们来看看nforce2_driver
370 static struct cpufreq_driver nforce2_driver = {
371         .name = "nforce2",
372         .verify = nforce2_verify,
373         .target = nforce2_target,
374         .get = nforce2_get,
375         .init = nforce2_cpu_init,
376         .exit = nforce2_cpu_exit,
377 };
在使用中会调用__cpufreq_driver_target 来设定频率。这个函数target方法或者target_index 来将freq设定到cpu的寄存器中。对这点不明白可以参考前面的博文.
在本例中实现了target方法.
在调用target之前会调用init方法,init方法就给出了cpu 这里支持的最大和最小频率。如358行359所示.
309 static int nforce2_cpu_init(struct cpufreq_policy *policy)
310 {
356 
357         /* cpuinfo and default policy values */
358         policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100;
359         policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100;
360         policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
361 
362         return 0;
363 }
其次看看target是如何设定freq的
252 static int nforce2_target(struct cpufreq_policy *policy,
253                           unsigned int target_freq, unsigned int relation)
254 {
255 /*        unsigned long         flags; */
256         struct cpufreq_freqs freqs;
257         unsigned int target_fsb;
258 
259         if ((target_freq > policy->max) || (target_freq < policy->min))
260                 return -EINVAL;
261 
262         target_fsb = target_freq / (fid * 100);
263 
264         freqs.old = nforce2_get(policy->cpu);
265         freqs.new = target_fsb * fid * 100;
266 
267         if (freqs.old == freqs.new)
268                 return 0;
269 
270         pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
271                freqs.old, freqs.new);
272 
273         cpufreq_freq_transition_begin(policy, &freqs);
274 
275         /* Disable IRQs */
276         /* local_irq_save(flags); */
277 
278         if (nforce2_set_fsb(target_fsb) < 0)
279                 pr_err("Changing FSB to %d failed\n", target_fsb);
280         else
281                 pr_debug("Changed FSB successfully to %d\n",
282                         target_fsb);
283 
284         /* Enable IRQs */
285         /* local_irq_restore(flags); */
286 
287         cpufreq_freq_transition_end(policy, &freqs, 0);
288 
289         return 0;
290 }
在262上所处      target_fsb = target_freq / (fid * 100);
可以看到是通过nforce2_set_fsb(target_fsb)来设定的频率的。
169 static int nforce2_set_fsb(unsigned int fsb)
170 {
171         u32 temp = 0;
172         unsigned int tfsb;
173         int diff;
174         int pll = 0;
175 
176         if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
177                 pr_err("FSB %d is out of range!\n", fsb);
178                 return -EINVAL;
179         }
180 
181         tfsb = nforce2_fsb_read(0);
182         if (!tfsb) {
183                 pr_err("Error while reading the FSB\n");
184                 return -EINVAL;
185         }
186 
187         /* First write? Then set actual value */
188         pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
189         if (!temp) {
190                 pll = nforce2_calc_pll(tfsb);
191 
192                 if (pll < 0)
193                         return -EINVAL;
194 
195                 nforce2_write_pll(pll);
196         }
197 
198         /* Enable write access */
199         temp = 0x01;
200         pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp);
201 
202         diff = tfsb - fsb;
203 
204         if (!diff)
205                 return 0;
206 
207         while ((tfsb != fsb) && (tfsb <= max_fsb) && (tfsb >= min_fsb)) {
208                 if (diff < 0)
209                         tfsb++;
210                 else
211                         tfsb--;
212 
213                 /* Calculate the PLL reg. value */
214                 pll = nforce2_calc_pll(tfsb);
215                 if (pll == -1)
216                         return -EINVAL;
217 
218                 nforce2_write_pll(pll);
219 #ifdef NFORCE2_DELAY
220                 mdelay(NFORCE2_DELAY);
221 #endif
222         }
223 
224         temp = 0x40;
225         pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp);
226 
227         return 0;
228 }
229 
从214行可以看出在这个例子中是将通过nforce2_calc_pll将freq转成成pll 通过调用nforce2_write_pll来设定到pll寄存器中的
116 static void nforce2_write_pll(int pll)
117 {
118         int temp;
119 
120         /* Set the pll addr. to 0x00 */
121         pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0);
122 
123         /* Now write the value in all 64 registers */
124         for (temp = 0; temp <= 0x3f; temp++)
125                 pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll);
126 
127         return;
128 }
哈哈,125行终于看见真的是在写寄存器了吧



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值