exynos电源管理与功耗实例分析

来源:互联网 发布:高光谱数据平滑处理 编辑:程序博客网 时间:2024/06/05 01:02

最新的内核代码中,三星已经把exynos系列三款芯片的相关代码都加入主线版本。

cpufreq子系统下已经有支持exynos4210,exynos4212,exynos5250三款soc的代码。

exynos采用频率表的方式来管理cpu工作频点,并将内核输出的描述频率表的数据结构嵌入exynos_dvfs_info结构体。

struct exynos_dvfs_info {unsigned longmpll_freq_khz;unsigned intpll_safe_idx;unsigned intpm_lock_idx;unsigned intmax_support_idx;unsigned intmin_support_idx;struct clk*cpu_clk;unsigned int*volt_table;struct cpufreq_frequency_table*freq_table;void (*set_freq)(unsigned int, unsigned int);bool (*need_apll_change)(unsigned int, unsigned int);};

exynos 4210 定义了5个工作频率,范围在1.2GHz到200MHz之间。

exynos 4212定义了14个工作频率范围在1.5GHz到200MHz之间。

exynos 5250定义了16个工作频率范围在1.7GHz到200MHz之间。



不同频率级别之间切换主要是通过操作PLL和分频器来完成

static void exynos4210_set_frequency(unsigned int old_index,     unsigned int new_index){unsigned int tmp;if (old_index > new_index) {if (!exynos4210_pms_change(old_index, new_index)) {/* 1. Change the system clock divider values */exynos4210_set_clkdiv(new_index);/* 2. Change just s value in apll m,p,s value */tmp = __raw_readl(EXYNOS4_APLL_CON0);tmp &= ~(0x7 << 0);tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);__raw_writel(tmp, EXYNOS4_APLL_CON0);} else {/* Clock Configuration Procedure *//* 1. Change the system clock divider values */exynos4210_set_clkdiv(new_index);/* 2. Change the apll m,p,s value */exynos4210_set_apll(new_index);}} else if (old_index < new_index) {if (!exynos4210_pms_change(old_index, new_index)) {/* 1. Change just s value in apll m,p,s value */tmp = __raw_readl(EXYNOS4_APLL_CON0);tmp &= ~(0x7 << 0);tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);__raw_writel(tmp, EXYNOS4_APLL_CON0);/* 2. Change the system clock divider values */exynos4210_set_clkdiv(new_index);} else {/* Clock Configuration Procedure *//* 1. Change the apll m,p,s value */exynos4210_set_apll(new_index);/* 2. Change the system clock divider values */exynos4210_set_clkdiv(new_index);}}}

针对PLL和CLKDIV的操作都被封装在exynos4210_set_apll 函数 exynos4210_set_clkdiv 函数中。if 分支,old_index 大于 new_index 表示降频操作。先配置 CLKDIV 到新的级别,再调整 APLL 到新的级别。else if分支,old_index 小于 new_index 表示倍频操作。先配置 APLL 到新的级别,再调整 CLKDIV 到新的级别。

exynos4210_set_clkdiv函数通过读写分频器相关的寄存器来控制分频器,每个频率级别相关的参数值则放在一个二维数组表中。

static struct cpufreq_clkdiv exynos4210_clkdiv_table[CPUFREQ_LEVEL_END];
exynos4210是双核处理器,分频器的配置有一定的约束关系,exynos4210_clkdiv_table中的值根据两组参数
static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END][7] = {/* * Clock divider value for following * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH, *DIVATB, DIVPCLK_DBG, DIVAPLL } *//* ARM L0: 1200MHz */{ 0, 3, 7, 3, 4, 1, 7 },/* ARM L1: 1000MHz */{ 0, 3, 7, 3, 4, 1, 7 },/* ARM L2: 800MHz */{ 0, 3, 7, 3, 3, 1, 7 },/* ARM L3: 500MHz */{ 0, 3, 7, 3, 3, 1, 7 },/* ARM L4: 200MHz */{ 0, 1, 3, 1, 3, 1, 0 },};static unsigned int clkdiv_cpu1[CPUFREQ_LEVEL_END][2] = {/* * Clock divider value for following * { DIVCOPY, DIVHPM } *//* ARM L0: 1200MHz */{ 5, 0 },/* ARM L1: 1000MHz */{ 4, 0 },/* ARM L2: 800MHz */{ 3, 0 },/* ARM L3: 500MHz */{ 3, 0 },/* ARM L4: 200MHz */{ 3, 0 },};
exynos4210_set_apll 函数通过读写 APLL 相关的寄存器来控制 APLL 的输出,相关的配置参数定义在exynos4210_apll_pms_table 数组中:

static unsigned int exynos4210_apll_pms_table[CPUFREQ_LEVEL_END] = {/* APLL FOUT L0: 1200MHz */((150 << 16) | (3 << 8) | 1),/* APLL FOUT L1: 1000MHz */((250 << 16) | (6 << 8) | 1),/* APLL FOUT L2: 800MHz */((200 << 16) | (6 << 8) | 1),/* APLL FOUT L3: 500MHz */((250 << 16) | (6 << 8) | 2),/* APLL FOUT L4: 200MHz */((200 << 16) | (6 << 8) | 3),};

PLL的操作流程,根据代码注释,可以看出一点端倪。

a) 切换ARM核的时钟到MPLL

b) 设置APLL的锁频时间

c)配置APLL的调频参数

d)开始调频,并等待频率锁定

e)把ARM核的时钟切回APLL



原创粉丝点击