首页 > 代码库 > 一个Linux平台PM功能初探
一个Linux平台PM功能初探
WatchDog
用户空间节点
/dev/watchdog
/sys/bus/platform/devices/zx29_ap_wdt.0
/sys/bus/platform/drivers/zx29_ap_wdt
时钟资源
arch/arm/mach-zx297520v3/include/mach/iomap.h #define ZX_LSP_CRPM_BASE (ZX_LSP_BASE) drivers/clk/zte/clk-zx297520v3.c /************************************************************************** static struct zx29_hwclk ap_wdt_apb = static struct zx29_hwclk ap_wdt_work =
struct clk_lookup periph_clocks_lookups[] = { }; |
platform设备代码
中:
arch/arm/mach-zx297520v3/include/mach/iomap.h #define ZX_AP_WDT_BASE (ZX_LSP_BASE + 0xE000) arch/arm/mach-zx297520v3/zx297520v3-devices.c (这其中的资源会在probe中使用到) static struct resource wdt_res[] = { static struct platform_device zx297520v2_wdt_device = { struct platform_device *zx29_device_table[] __initdata=http://www.mamicode.com/{ … |
platform驱动代码
drivers/watchdog/zx29_wdt.c中:
时钟相关
watchdog_init->platform_driver_register(&zx29_wdt_driver)-|->zx29_wdt_probe -|->__devexit_p(zx29_wdt_remove) -|->zx29_wdt_shutdown -|->zx29_wdt_suspend -|->zx29_wdt_resume watchdog_exit->platform_driver_unregister(&zx29_wdt_driver) |
cpuidle
menuconfig
CONFIG_CPU_IDLE=y |
cpuidle driver
在本平台中cpuidle driver没有作为单一的模块,二是放在zx_pm_init中进行。
drivers/soc/zte/power/zx-cpuidle.c
zx_pm_init-|->pm_debug_init->idle_debug_init (/sys/zte_pm/cpuidle/) |->zx_cpuidle_init-> |
drivers/soc/zte/power/zx297520v3-cpuidle.c中定义了cpuidle的状态
#define WHOLE_CHIP_EXIT_LATENCY (4000) /* us */ #define LP2_DEFAULT_EXIT_LATENCY (500 + WHOLE_CHIP_EXIT_LATENCY) /* us */ #define LP2_DELTA_EXIT_LATENCY (100) /* us -- for timer setting refresh time, should > 2us.
static struct cpuidle_state zx297520v3_cpuidle_set[] __initdata =http://www.mamicode.com/ |
cpu_idle在start_kernel->rest_init->cpu_idle->while(1)中调用。cpu_idle调用cpuidle_idle_call:
cpu_idle->cpuidle_idle_call-|->trace_cpu_idle_rcuidle(next_state, dev->cpu); |->trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); |
cpuidle_curr_governor->select(drv, dev) 根据当前的governor,选择合适的cpuidle状态 entered_state = cpuidle_enter_state(dev, drv, next_state); cpuidle_curr_governor->reflect(dev, entered_state) |
cpuidle_curr_governor在cpuidle_switch_governor中进行设置,一个是在cpuidle_register_governor注册时的时候,另一个是在store_current_governor通过sysfs节点设置cpuidle governor的时候。由于默认使用的是menu_governor,下面就来重点分析一下:
static struct cpuidle_governor menu_governor = {
.name = "menu",
.rating = 20,
.enable = menu_enable_device,
.select = menu_select,
.reflect = menu_reflect,
.owner = THIS_MODULE,
};
》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
cpuidle_enter_state是执行根据governor确定的状态执行,然后返回进入的状态值。
cpuidle_enable_device设置cpuidle_enter_ops的值,cpuidle_enter_ops = drv->en_core_tk_irqen?cpuidle_enter_tk:cpuidle_enter;
cpuidle_enter调用target_state->enter(dev, drv, index);,指向zx_enter_idle。
zx_enter_idle-|->zx_pm_idle_prepare |
cpuidle core
cpuidle governors
cpufreq
cpufreq driver
drivers/soc/zte/power/zx-cpufreq.c
drvers/soc/zte/power/zx297520v3-cpufreq.c
设置cpufreq的DVFS数据,在struct zx_dvfs_info中。
struct zx_dvfs_info { |
cpufreq driver想初始化DVFS通过调用zx29xx_cpufreq_init。
static int zx297520v3_cpufreq_init(struct zx_dvfs_info *info) cpu_clk = clk_get(NULL, "cpu_clk"); info->freq_cur_idx = L1; cpufreq_driver_inited = 1; INIT_DELAYED_WORK_DEFERRABLE(&pm_freq_work, pm_freq_func);
return 0; |
cpu_clk如下:
static struct zx29_hwclk cpu_work = { CLK_ZX29_CONFIG(NULL, "cpu_clk", &cpu_work_clk), |
这里通过zx297520v3_volt_table和zx297520v3_freq_table来达到OPP的概念,zx297520v3_set_frequency作为设置频率的底层函数。
static unsigned int zx297520v3_volt_table[CPUFREQ_LEVEL_END] = { static struct cpufreq_frequency_table zx297520v3_freq_table[] = { 实际的频率只有两种,而且不可以调压 |
cpufreq governors
cpufreq core
cpu hotplug
由于是单核CPU,所以不能使用hotplug功能。
wakelock
kernel/power/main.c
#ifdef CONFIG_PM_WAKELOCKS static ssize_t wake_lock_store(struct kobject *kobj, power_attr(wake_lock); static ssize_t wake_unlock_show(struct kobject *kobj, static ssize_t wake_unlock_store(struct kobject *kobj, power_attr(wake_unlock); #endif /* CONFIG_PM_WAKELOCKS */
static struct attribute * g[] = { |
kernel/power/wakelock.c
增加wakelock tracepoint
修改config.linux:
CONFIG_PM_DEBUG=y
CONFIG_PM_SLEEP_DEBUG=y
CONFIG_FTRACE=y
CONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y
CONFIG_KPROBES=y
CONFIG_KPROBES_ON_FTRACE=y
|
修改include/trace/events/power.h,增加wakelock相关trace包括pm_wake_lock和pm_wake_unlock。
修改kernel/power/wakelock.c,在pm_wake_lock和pm_wake_unlock中添加trace。
Index: wakelock.c |
Runtime PM
Suspend and Resume
Clock、Regulator
一个Linux平台PM功能初探