📄 dpm.c
字号:
/* * arch/arm/mach-mp200/dpm.c * * MP200-specific DPM support * * Copyright (C) 2005-2006 NEC Electronics Corporation * * 2005 (c) MontaVista Software, Inc. This file is licensed under the * terms of the GNU General Public License version 2. This program is * licensed "as is" without any warranty of any kind, whether express * or implied. * */#include <linux/config.h>#include <linux/init.h>#include <linux/dpm.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/arch/pwc.h>#include <asm/arch/pm.h>#include "pm.h"#define MP200_LOGIC_V_MIN 1000#define MP200_LOGIC_V_MAX 1400#define MP200_LOGIC_V_DEF 1200/* convert PWC value and voltage (mV) */#define CONV_VOLT_TO_VAL(volt) (((volt) - 800) / 20)#define CONV_VAL_TO_VOLT(val) (((val) * 20) + 800)static void mp200_dpm_scale_voltage_L0(int voltage){ /* not support */}static void mp200_dpm_scale_voltage_L1(int voltage){ /* not support */}static int mp200_dpm_get_voltage_L0(void){ /* not support */ return MP200_LOGIC_V_DEF;}static int mp200_dpm_get_voltage_L1(void){ /* not support */ return MP200_LOGIC_V_DEF;}static int mp200_dpm_set_opt(struct dpm_opt *cur, struct dpm_opt *new){ unsigned long flags; if (new->md_opt.cpu == 0) {#ifdef CONFIG_PM mp200_pm_sleep(new->md_opt.sleep_mode); /* Here when we wake up. Recursive call to switch back to * to task state. */ dpm_set_os(DPM_TASK_STATE);#endif return 0; } local_irq_save(flags); if (new->md_opt.cpu != cur->md_opt.cpu) { mp200_pm_set_pll(new->md_opt.cpu); } if (new->md_opt.v0 != cur->md_opt.v0) { mp200_dpm_scale_voltage_L0(new->md_opt.v0); } if (new->md_opt.v1 != cur->md_opt.v1) { mp200_dpm_scale_voltage_L1(new->md_opt.v1); } local_irq_restore(flags); return 0;}/* Initialize the machine-dependent operating point from a list of parameters, * which has already been installed in the pp field of the operating point. * Some of the parameters may be specified with a value of -1 to indicate a * default value. */static int mp200_dpm_init_opt(struct dpm_opt *opt){ int v0 = opt->pp[DPM_MD_V_L0]; int v1 = opt->pp[DPM_MD_V_L1]; int cpu = opt->pp[DPM_MD_CPU]; int sleep_mode = opt->pp[DPM_MD_SLEEP_MODE]; struct dpm_md_opt *md_opt = &opt->md_opt; /* * Let's do some upfront error checking. If we fail any * of these, then the whole operating point is suspect * and therefore invalid. */ if ((cpu != -1) && (cpu != 0) && (cpu != MP200_PLL_248MHZ) && (cpu != MP200_PLL_124MHZ)) { printk(KERN_WARNING "%s: " "CPU_MODE parameter %d out of range for opt named \"%s\"\n", __FUNCTION__, cpu, opt->name); return -EINVAL; } if ((v0 != -1) && ((v0 < MP200_LOGIC_V_MIN) || (v0 > MP200_LOGIC_V_MAX))) { printk(KERN_WARNING "%s: " "Logic0 voltage can not be lower than %dmV and larger than %dmV\n" "Voltage %d out of range for opt named \"%s\"\n", __FUNCTION__, MP200_LOGIC_V_MIN, MP200_LOGIC_V_MAX, v0, opt->name); return -EINVAL; } if ((v1 != -1) && ((v1 < MP200_LOGIC_V_MIN) || (v1 > MP200_LOGIC_V_MAX))) { printk(KERN_WARNING "%s: " "Logic1 (CPUx and DSP core) voltage can not be" "lower than %dmV and larger than %dmV\n" "Voltage %d out of range for opt named \"%s\"\n", __FUNCTION__, MP200_LOGIC_V_MIN, MP200_LOGIC_V_MAX, v1, opt->name); return -EINVAL; } if ((sleep_mode != -1) && ((sleep_mode < PM_SLEEP_MODE_NONE) || (sleep_mode > PM_SLEEP_MODE_MAX))) { printk(KERN_WARNING "%s :" "SLEEP_MODE parameter sleep mode is invalid: " "%d out of range for opt named \"%s\"\n", __FUNCTION__, sleep_mode, opt->name); return -EINVAL; } if (v0 == -1) { md_opt->v0 = MP200_LOGIC_V_DEF; } else { md_opt->v0 = v0; } if (v1 == -1) { md_opt->v1 = MP200_LOGIC_V_DEF; } else { md_opt->v1 = v1; } if (cpu == -1) { md_opt->cpu = mp200_pm_get_pll(); if (md_opt->cpu != MP200_PLL_124MHZ) { md_opt->cpu = MP200_PLL_248MHZ; } } else { md_opt->cpu = cpu; } if (sleep_mode == -1) { md_opt->sleep_mode = PM_SLEEP_MODE_NONE; } else { md_opt->sleep_mode = sleep_mode; }#ifdef DPM_DEBUG printk("v0=%d\n", md_opt->v0); printk("v1=%d\n", md_opt->v1); printk("cpu=%d\n", md_opt->cpu); printk("sleep_mode=%d\n", md_opt->sleep_mode);#endif 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(). */static int mp200_dpm_get_opt(struct dpm_opt *opt){ struct dpm_md_opt *md_opt = &opt->md_opt; md_opt->v0 = mp200_dpm_get_voltage_L0(); md_opt->v1 = mp200_dpm_get_voltage_L1(); md_opt->cpu = mp200_pm_get_pll(); if (md_opt->cpu != MP200_PLL_124MHZ) { md_opt->cpu = MP200_PLL_248MHZ; } md_opt->sleep_mode = PM_SLEEP_MODE_NONE; return 0;}/**************************************************************************** * DPM Idle Handler ****************************************************************************/static void (*orig_idle) (void);static void mp200_dpm_idle(void){ extern void default_idle(void); if (orig_idle) orig_idle(); else default_idle();}/**************************************************************************** * Initialization/Exit ****************************************************************************/extern void (*pm_idle) (void);static void mp200_dpm_startup(void){ if (pm_idle != dpm_idle) { orig_idle = pm_idle; pm_idle = dpm_idle; }}static void mp200_dpm_cleanup(void){ pm_idle = orig_idle;}static int __init mp200_dpm_init(void){ printk("MP200 Dynamic Power Management\n"); dpm_md.init_opt = mp200_dpm_init_opt; dpm_md.set_opt = mp200_dpm_set_opt; dpm_md.get_opt = mp200_dpm_get_opt; dpm_md.check_constraint = dpm_default_check_constraint; dpm_md.idle = mp200_dpm_idle; dpm_md.startup = mp200_dpm_startup; dpm_md.cleanup = mp200_dpm_cleanup; return 0;}__initcall(mp200_dpm_init);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -