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

📄 dpm.c

📁 Linux 2.4 内核下动态电源管理(Dynamic Power Management)的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
#define PLL_NF_MAX  0x1ff#define PLL_NR_MAX  (0x1f+2)int dpm_jz_init_opt(struct dpm_opt *opt){	int clkdiv_decode[] = {-1, 0, 1, 2, 3, -1, 4, -1,			       5, -1, -1, -1, 6, -1, -1, -1,			       7, -1, -1, -1, -1, -1, -1, -1,			       8, -1, -1, -1, -1, -1, -1, -1,			       9};//	int v		= opt->pp[DPM_MD_V];	int pll_nf   	= opt->pp[DPM_MD_PLL_NF];	int pll_nr   	= opt->pp[DPM_MD_PLL_NR];	int pll_no   	= opt->pp[DPM_MD_PLL_NO];	int iclk_div	= opt->pp[DPM_MD_ICLK_DIV];	int sclk_div	= opt->pp[DPM_MD_SCLK_DIV];	int mclk_div	= opt->pp[DPM_MD_MCLK_DIV];	int pclk_div	= opt->pp[DPM_MD_PCLK_DIV];	struct dpm_md_opt *md_opt = &opt->md_opt;	/* Let's do some error checking. If we fail any of these, then the	 * whole operating point is suspect and therefore invalid.	 */	if (iclk_div && /* iclk_div=0 means sleep */	    ((pll_nf > PLL_NF_MAX) || (pll_nf < 0) ||	     (pll_nr > PLL_NR_MAX) || (pll_nr < 2) ||	     ((pll_no != 1) && (pll_no != 2) && (pll_no != 4)))) {		printk(KERN_WARNING "dpm_md_init_opt: "				 "PLL_NF/PLL_NR/PLL_NO specification "				 "(%u/%u/%u) out of range for opt named %s\n",				 pll_nf, pll_nr, pll_no, opt->name );		return -EINVAL;	}	if (check_divider(iclk_div) < 0) {		printk(KERN_WARNING "dpm_md_init_opt: "		       "ICLK_DIV specification "		       "(%u) out of range for opt named %s\n",		       iclk_div, opt->name );		return -EINVAL;	}	if (check_divider(sclk_div) < 0) {		printk(KERN_WARNING "dpm_md_init_opt: "		       "SCLK_DIV specification "		       "(%u) out of range for opt named %s\n",		       sclk_div, opt->name );		return -EINVAL;	}	if (check_divider(mclk_div) < 0) {		printk(KERN_WARNING "dpm_md_init_opt: "		       "MCLK_DIV specification "		       "(%u) out of range for opt named %s\n",		       mclk_div, opt->name );		return -EINVAL;	}	if (check_divider(pclk_div) < 0) {		printk(KERN_WARNING "dpm_md_init_opt: "		       "PCLK_DIV specification "		       "(%u) out of range for opt named %s\n",		       pclk_div, opt->name );		return -EINVAL;	}	/* make sure the operating point follows the syncronous scalable mode rules */	if (iclk_div == 0) {		sclk_div = mclk_div = pclk_div = 0; /* go to sleep */	}	else {		if ((sclk_div == 0) || (mclk_div == 0) || (pclk_div == 0)) {			printk(KERN_WARNING "dpm_md_init_opt: "			       "SCLK, MCLK and PCLK specification "			       "(%u %u %u) cannot be zero for opt named %s\n",			       sclk_div, mclk_div, pclk_div, opt->name );			return -EINVAL;		}		/* ICLK must be integral multiple of SCLK */		{			int d = sclk_div / iclk_div;			if (d * iclk_div != sclk_div) {				printk(KERN_WARNING "dpm_md_init_opt: "				       "ICLK and SCLK specification "				       "ICLK(%u) must be integral multiple of SCLK(%u) for opt named %s\n",				       iclk_div, sclk_div, opt->name );				return -EINVAL;			}		}		/* SCLK must be equal to MCLK or twice of MCLK */		{			if ((sclk_div != mclk_div) && (sclk_div * 2 != mclk_div)) {				printk(KERN_WARNING "dpm_md_init_opt: "				       "SCLK and MCLK specification "				       "SCLK(%u) must be equal to MCLK or twice of MCLK(%u) for opt named %s\n",				       sclk_div, mclk_div, opt->name );				return -EINVAL;			}		}		/* SCLK must be integral multiple of PCLK */		{			int d = pclk_div / sclk_div;			if (d * sclk_div != pclk_div) {				printk(KERN_WARNING "dpm_md_init_opt: "				       "SCLK and PCLK specification "				       "SCLK(%u) must be integral multiple of PCLK(%u) for opt named %s\n",				       sclk_div, pclk_div, opt->name );				return -EINVAL;			}		}		/* MCLK must be integral multiple of PCLK */		{			int d = pclk_div / mclk_div;			if (d * mclk_div != pclk_div) {				printk(KERN_WARNING "dpm_md_init_opt: "				       "MCLK and PCLK specification "				       "MCLK(%u) must be integral multiple of PCLK(%u) for opt named %s\n",				       mclk_div, pclk_div, opt->name );				return -EINVAL;			}		}	}	/* PLL frequency */	if (iclk_div == 0) {		md_opt->pll = 0;	}	else {		md_opt->pll = JZ_EXTAL * pll_nf / (pll_nr * pll_no);		md_opt->regs.plcr1 = ((pll_nf-2) << 23) | ((pll_nr-2) << 18) | ((pll_no - 1) << 16);		md_opt->regs.plcr1_mask = CPM_PLCR1_PLL1FD_MASK | CPM_PLCR1_PLL1RD_MASK | CPM_PLCR1_PLL1OD_MASK;	} 	/* CPU clock */	if (iclk_div == 0) 		/* zero means sleep for cpu */		md_opt->cpu = 0;	else {		md_opt->cpu = md_opt->pll / iclk_div;		md_opt->regs.cfcr |= (clkdiv_decode[iclk_div] << CPM_CFCR_IFR_BIT);		md_opt->regs.cfcr_mask |= CPM_CFCR_IFR_MASK;	}	/* System bus clock */	if (sclk_div > 0) {		md_opt->sys = md_opt->pll / sclk_div;		md_opt->regs.cfcr |= (clkdiv_decode[sclk_div] << CPM_CFCR_SFR_BIT);		md_opt->regs.cfcr_mask |= CPM_CFCR_SFR_MASK;	}	/* Memory clock */	if (mclk_div > 0) {		md_opt->mem = md_opt->pll / mclk_div;		md_opt->regs.cfcr |= (clkdiv_decode[mclk_div] << CPM_CFCR_MFR_BIT);		md_opt->regs.cfcr_mask |= CPM_CFCR_MFR_MASK;	}	/* Peripheral bus clock */	if (pclk_div > 0) {		md_opt->per = md_opt->pll / pclk_div;		md_opt->regs.cfcr |= (clkdiv_decode[pclk_div] << CPM_CFCR_PFR_BIT);		md_opt->regs.cfcr_mask |= CPM_CFCR_PFR_MASK;	}	/* Voltage */	md_opt->v = 1800; /* not chageable by software */	md_opt->lpj = compute_lpj(loops_per_jiffy, __cpm_get_iclk(), md_opt->cpu);	return 0;}/* Fully determine the current machine-dependent operating point, and fill in a   structure presented by the caller. This should only be called when the   dpm_sem is held. This call can return an error if the system is currently at   an operating point that could not be constructed by dpm_md_init_opt(). */int dpm_jz_get_opt(struct dpm_opt *opt){	struct dpm_md_opt *md_opt = &opt->md_opt;	md_opt->v = 1800; /* not chageable by software */	md_opt->pll = __cpm_get_pllout();	md_opt->cpu = __cpm_get_iclk();	md_opt->sys = __cpm_get_sclk();	md_opt->mem = __cpm_get_mclk();	md_opt->per = __cpm_get_pclk();	md_opt->lpj = loops_per_jiffy;	md_opt->regs.plcr1 = REG_CPM_PLCR1;	md_opt->regs.plcr1_mask = (CPM_PLCR1_PLL1FD_MASK | CPM_PLCR1_PLL1RD_MASK | CPM_PLCR1_PLL1OD_MASK);	md_opt->regs.cfcr = REG_CPM_CFCR;	md_opt->regs.cfcr_mask = (CPM_CFCR_MFR_MASK | CPM_CFCR_LFR_MASK | CPM_CFCR_PFR_MASK | CPM_CFCR_SFR_MASK | CPM_CFCR_IFR_MASK);	md_opt->regs.cfcr2 = REG_CPM_CFCR2;	md_opt->regs.cfcr2_mask = CPM_CFCR2_PXFR_MASK;	return 0;}/**************************************************************************** *  DPM Idle Handler ****************************************************************************//* Check for pending external interrupts.  If so, the entry to a low-power   idle is preempted. */int return_from_idle_immediate(void){	return 1;}/**************************************************************************** * Machine-dependent /proc/driver/dpm/md entries ****************************************************************************/static inline int p5d(char *buf, unsigned hz){	return sprintf(buf, "%d.%02d\t", (hz/1000000), (hz%1000000)/10000);}static int dpm_proc_print_opt(char *buf, struct dpm_opt *opt){        int len = 0;        struct dpm_md_opt *md_opt = &opt->md_opt;        len += sprintf(buf + len, "%12s  ", opt->name);        len += p5d(buf + len, md_opt->pll);        len += p5d(buf + len, md_opt->cpu);        len += p5d(buf + len, md_opt->sys);        len += p5d(buf + len, md_opt->mem);        len += p5d(buf + len, md_opt->per);        len += sprintf(buf + len, "\n");        return len;}int read_proc_dpm_md_opts(char *page, char **start, off_t offset,		      int count, int *eof, void *data){	int len = 0;	int limit = offset + count;	struct dpm_opt *opt;	struct list_head *opt_list;		/* FIXME: For now we assume that the complete table,	 * formatted, fits within one page */	if (offset >= PAGE_SIZE)		return 0;	if (dpm_lock_interruptible())		return -ERESTARTSYS;	if (!dpm_initialized)		len += sprintf(page + len, "DPM is not initialized\n");	else if (!dpm_enabled)		len += sprintf(page + len, "DPM is disabled\n");	else {		len += sprintf(page + len,			       "The active DPM policy is \"%s\"\n",			       dpm_active_policy->name);		len += sprintf(page + len, 			       "The current operating point is \"%s\"\n",			       dpm_active_opt->name);	}	if (dpm_initialized) {		len += sprintf(page + len, 			       "Table of all defined operating points, "			       "frequencies in MHz:\n");		len += sprintf(page + len, 				"    Name       PLL\tCPU\tSYS\tMEM\tPER\n");		list_for_each(opt_list, &dpm_opts) {			opt = list_entry(opt_list, struct dpm_opt, list);			if (len >= PAGE_SIZE)				BUG();			if (len >= limit)				break;			len += dpm_proc_print_opt(page + len, opt);		}#define TO_MHZ(x) (x/1000000),(x%1000000)/10000		len += sprintf(page +len,"\nCurrent values PLL\tCPU\tSYS\tMEM\tPER\n");		len += sprintf(page +len,"\n               %d.%02d\t%d.%02d\t%d.%02d\t%d.%02d\t%d.%02d\n",			       TO_MHZ(__cpm_get_pllout()),			       TO_MHZ(__cpm_get_iclk()),			       TO_MHZ(__cpm_get_sclk()), 			       TO_MHZ(__cpm_get_mclk()),			       TO_MHZ(__cpm_get_pclk()));		//calibrate_delay();	}	dpm_unlock();	*eof = 1;	if (offset >= len)		return 0;	*start = page + offset;	return min(count, len - (int)offset);}/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * * /proc/driver/dpm/md/cmd (Write-only) * *  This is a catch-all, simple command processor for the Innovator DPM *  implementation. These commands are for experimentation and development *  _only_, and may leave the system in an unstable state. * *  No commands defined now. * ****************************************************************************/int write_proc_dpm_md_cmd (struct file *file, const char *buffer,		       unsigned long count, void *data){	char *buf, *tok, *s;	char *whitespace = " \t\r\n";	int ret = 0;	if (current->uid != 0)		return -EACCES;	if (count == 0)		return 0;	if (!(buf = kmalloc(count + 1, GFP_KERNEL)))		return -ENOMEM;	if (copy_from_user(buf, buffer, count)) {		kfree(buf);		return -EFAULT;	}	buf[count] = '\0';	s = buf + strspn(buf, whitespace);	tok = strsep(&s, whitespace);		if (strcmp(tok, "define-me") == 0) {		;	} else {		ret = -EINVAL;	}		kfree(buf);	if (ret == 0)		return count;	else 		return ret;}/* * Support an Jz board */static int dpm_jz_bd_init(void){	return 0;}static void dpm_jz_bd_exit(void){	return;}void dpm_jz_board_setup(void){	dpm_bd.init		= dpm_jz_bd_init;	dpm_bd.exit		= dpm_jz_bd_exit;	dpm_bd.check_v		= NULL;	dpm_bd.set_v_pre 	= NULL;	dpm_bd.set_v_post 	= NULL;}/**************************************************************************** * Initialization/Exit ****************************************************************************/void dpm_jz_cleanup(void){	dpm_bd.exit();}extern void (*pm_idle)(void);   int __init dpm_jz_init(void){	dpm_md.init		= NULL;	dpm_md.init_opt		= dpm_jz_init_opt;	dpm_md.set_opt		= dpm_default_set_opt;	dpm_md.get_opt		= dpm_jz_get_opt;	dpm_md.idle_set_parms	= NULL;	dpm_md.cleanup		= dpm_jz_cleanup;	dpm_jz_board_setup();	dpm_bd.init();#ifdef CONFIG_DPM_UTIMER	init_utimer(&set_opt_utimer);#endif#ifdef CONFIG_DPM_IDLE	pm_idle = dpm_idle;#endif	printk("Jz Dynamic Power Management\n");	return 0;}__initcall(dpm_jz_init);

⌨️ 快捷键说明

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