⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cpufreq_32.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org> *  Copyright (C) 2004        John Steele Scott <toojays@toojays.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * TODO: Need a big cleanup here. Basically, we need to have different * cpufreq_driver structures for the different type of HW instead of the * current mess. We also need to better deal with the detection of the * type of machine. * */#include <linux/module.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/adb.h>#include <linux/pmu.h>#include <linux/slab.h>#include <linux/cpufreq.h>#include <linux/init.h>#include <linux/sysdev.h>#include <linux/hardirq.h>#include <asm/prom.h>#include <asm/machdep.h>#include <asm/irq.h>#include <asm/pmac_feature.h>#include <asm/mmu_context.h>#include <asm/sections.h>#include <asm/cputable.h>#include <asm/time.h>#include <asm/system.h>#include <asm/mpic.h>#include <asm/keylargo.h>/* WARNING !!! This will cause calibrate_delay() to be called, * but this is an __init function ! So you MUST go edit * init/main.c to make it non-init before enabling DEBUG_FREQ */#undef DEBUG_FREQ/* * There is a problem with the core cpufreq code on SMP kernels, * it won't recalculate the Bogomips properly */#ifdef CONFIG_SMP#warning "WARNING, CPUFREQ not recommended on SMP kernels"#endifextern void low_choose_7447a_dfs(int dfs);extern void low_choose_750fx_pll(int pll);extern void low_sleep_handler(void);/* * Currently, PowerMac cpufreq supports only high & low frequencies * that are set by the firmware */static unsigned int low_freq;static unsigned int hi_freq;static unsigned int cur_freq;static unsigned int sleep_freq;/* * Different models uses different mechanisms to switch the frequency */static int (*set_speed_proc)(int low_speed);static unsigned int (*get_speed_proc)(void);/* * Some definitions used by the various speedprocs */static u32 voltage_gpio;static u32 frequency_gpio;static u32 slew_done_gpio;static int no_schedule;static int has_cpu_l2lve;static int is_pmu_based;/* There are only two frequency states for each processor. Values * are in kHz for the time being. */#define CPUFREQ_HIGH                  0#define CPUFREQ_LOW                   1static struct cpufreq_frequency_table pmac_cpu_freqs[] = {	{CPUFREQ_HIGH, 		0},	{CPUFREQ_LOW,		0},	{0,			CPUFREQ_TABLE_END},};static struct freq_attr* pmac_cpu_freqs_attr[] = {	&cpufreq_freq_attr_scaling_available_freqs,	NULL,};static inline void local_delay(unsigned long ms){	if (no_schedule)		mdelay(ms);	else		msleep(ms);}#ifdef DEBUG_FREQstatic inline void debug_calc_bogomips(void){	/* This will cause a recalc of bogomips and display the	 * result. We backup/restore the value to avoid affecting the	 * core cpufreq framework's own calculation.	 */	extern void calibrate_delay(void);	unsigned long save_lpj = loops_per_jiffy;	calibrate_delay();	loops_per_jiffy = save_lpj;}#endif /* DEBUG_FREQ *//* Switch CPU speed under 750FX CPU control */static int cpu_750fx_cpu_speed(int low_speed){	u32 hid2;	if (low_speed == 0) {		/* ramping up, set voltage first */		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);		/* Make sure we sleep for at least 1ms */		local_delay(10);		/* tweak L2 for high voltage */		if (has_cpu_l2lve) {			hid2 = mfspr(SPRN_HID2);			hid2 &= ~0x2000;			mtspr(SPRN_HID2, hid2);		}	}#ifdef CONFIG_6xx	low_choose_750fx_pll(low_speed);#endif	if (low_speed == 1) {		/* tweak L2 for low voltage */		if (has_cpu_l2lve) {			hid2 = mfspr(SPRN_HID2);			hid2 |= 0x2000;			mtspr(SPRN_HID2, hid2);		}		/* ramping down, set voltage last */		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);		local_delay(10);	}	return 0;}static unsigned int cpu_750fx_get_cpu_speed(void){	if (mfspr(SPRN_HID1) & HID1_PS)		return low_freq;	else		return hi_freq;}/* Switch CPU speed using DFS */static int dfs_set_cpu_speed(int low_speed){	if (low_speed == 0) {		/* ramping up, set voltage first */		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);		/* Make sure we sleep for at least 1ms */		local_delay(1);	}	/* set frequency */#ifdef CONFIG_6xx	low_choose_7447a_dfs(low_speed);#endif	udelay(100);	if (low_speed == 1) {		/* ramping down, set voltage last */		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);		local_delay(1);	}	return 0;}static unsigned int dfs_get_cpu_speed(void){	if (mfspr(SPRN_HID1) & HID1_DFS)		return low_freq;	else		return hi_freq;}/* Switch CPU speed using slewing GPIOs */static int gpios_set_cpu_speed(int low_speed){	int gpio, timeout = 0;	/* If ramping up, set voltage first */	if (low_speed == 0) {		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);		/* Delay is way too big but it's ok, we schedule */		local_delay(10);	}	/* Set frequency */	gpio = 	pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);	if (low_speed == ((gpio & 0x01) == 0))		goto skip;	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio,			  low_speed ? 0x04 : 0x05);	udelay(200);	do {		if (++timeout > 100)			break;		local_delay(1);		gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0);	} while((gpio & 0x02) == 0); skip:	/* If ramping down, set voltage last */	if (low_speed == 1) {		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);		/* Delay is way too big but it's ok, we schedule */		local_delay(10);	}#ifdef DEBUG_FREQ	debug_calc_bogomips();#endif	return 0;}/* Switch CPU speed under PMU control */static int pmu_set_cpu_speed(int low_speed){	struct adb_request req;	unsigned long save_l2cr;	unsigned long save_l3cr;	unsigned int pic_prio;	unsigned long flags;	preempt_disable();#ifdef DEBUG_FREQ	printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));#endif	pmu_suspend();	/* Disable all interrupt sources on openpic */ 	pic_prio = mpic_cpu_get_priority();	mpic_cpu_set_priority(0xf);	/* Make sure the decrementer won't interrupt us */	asm volatile("mtdec %0" : : "r" (0x7fffffff));	/* Make sure any pending DEC interrupt occurring while we did	 * the above didn't re-enable the DEC */	mb();	asm volatile("mtdec %0" : : "r" (0x7fffffff));	/* We can now disable MSR_EE */	local_irq_save(flags);	/* Giveup the FPU & vec */	enable_kernel_fp();#ifdef CONFIG_ALTIVEC	if (cpu_has_feature(CPU_FTR_ALTIVEC))		enable_kernel_altivec();#endif /* CONFIG_ALTIVEC */	/* Save & disable L2 and L3 caches */	save_l3cr = _get_L3CR();	/* (returns -1 if not available) */	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */	/* Send the new speed command. My assumption is that this command	 * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep	 */	pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed);	while (!req.complete)		pmu_poll();	/* Prepare the northbridge for the speed transition */	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1);	/* Call low level code to backup CPU state and recover from	 * hardware reset	 */	low_sleep_handler();	/* Restore the northbridge */	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0);	/* Restore L2 cache */	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) 		_set_L2CR(save_l2cr);	/* Restore L3 cache */	if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) 		_set_L3CR(save_l3cr);	/* Restore userland MMU context */	set_context(current->active_mm->context.id, current->active_mm->pgd);#ifdef DEBUG_FREQ	printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));#endif	/* Restore low level PMU operations */	pmu_unlock();	/* Restore decrementer */	wakeup_decrementer();	/* Restore interrupts */ 	mpic_cpu_set_priority(pic_prio);	/* Let interrupts flow again ... */	local_irq_restore(flags);#ifdef DEBUG_FREQ	debug_calc_bogomips();#endif	pmu_resume();	preempt_enable();	return 0;}static int do_set_cpu_speed(int speed_mode, int notify){	struct cpufreq_freqs freqs;	unsigned long l3cr;	static unsigned long prev_l3cr;	freqs.old = cur_freq;	freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;	freqs.cpu = smp_processor_id();	if (freqs.old == freqs.new)		return 0;	if (notify)		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);	if (speed_mode == CPUFREQ_LOW &&	    cpu_has_feature(CPU_FTR_L3CR)) {		l3cr = _get_L3CR();		if (l3cr & L3CR_L3E) {			prev_l3cr = l3cr;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -