linux clk时钟源管理
硬件資源越來越龐大和復雜,內核的另一個挑戰就是要便捷的管理這些資源。同時,面對如此之多的平臺不同的CPU,管理機制需要統一適用,這就需要對資源的管理抽象到更加通用的層次。CPU中各個模塊都需要時鐘驅動,內核需要一種機制能通用所有的平臺,方便的管理CPU上所有的clk資源。這里分析Linux對clk的管理。
Linux version: 2.6.38
平臺: i.mx53 (mxc),以下所有平臺相關部分都特指i.mx53
涉及的源文件有:
include/linux/clk.hdrivers/clk/clkdev.carch/arm/plat-mxc/clock.carch/arm/mach-mx5/clock.c
1. clk通用接口
內核定義了一套標準的接口(include/linux/clk.h),用于所有的平臺之上。每個時鐘源對象使用一個struct clk結構來表示。而struct clk結構的具體內容由各平臺自己定義。clk.h頭文件定義了操作一個clk對象的所有接口。內核的其他地方可以也只能使用clk.h中提供的這些接口函數來操作clk。
struct clk *clk_get(struct device *dev, const char *id); int clk_enable(struct clk *clk); void clk_disable(struct clk *clk); unsigned long clk_get_rate(struct clk *clk); void clk_put(struct clk *clk); long clk_round_rate(struct clk *clk, unsigned long rate); int clk_set_rate(struct clk *clk, unsigned long rate); int clk_set_parent(struct clk *clk, struct clk *parent); struct clk *clk_get_parent(struct clk *clk); struct clk *clk_get_sys(const char *dev_id, const char *con_id); int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, struct device *dev);
2. struct clk
clk結構體是平臺相關的。在arch/arm/mach-mx5/clock.c中會預先描述CPU中所有的clk對象。
parent - clk是由parent分出來的。那么如果parent關閉了,當前clk也就沒有了。secondary - 第二時鐘源,用于enable/disable當前clk。usecount - 引用計數。get_rate, set_rate, enable, disable, set_parent - 很顯然,這些函數指針指到實際操作的函數。clk.h中的各接口函數最后都會調用到這里的函數指針。函數指針是隔離變化的最好辦法,在這里一下就把層次抽象出來了。
2. clocks鏈表
arch/arm/mach-mx5/clock.c中不僅定義了所有的clk對象,而且每個clk對象還要對應一個struct clk_lookup結構。在初始化時,會將所有的clk_loopup結構添加進入clocks鏈表中。
struct clk_lookup {
	struct list_head	node;
	const char		*dev_id;
	const char		*con_id;
	struct clk		*clk;
};
clk_lookup,顧名思義就知道它是用來查找struct clk結構的。有了它,就可以通過設備名或時鐘源的名字來找到相應的struct clk結構。鏈表操作位于drivers/clk/clkdev.c
3. clk平臺通用操作
arch/arm/plat-mxc/clock.c源文件中定義了mxc平臺clock的通用操作接口。
enable/disable函數中可以看到引用計數usecount的作用。一個clk只有當其usecount為0的時候才會做實際的打開動作,也只有usecount為0時才能確認沒有被任何其他設備使用,可以禁止了。層次關系被遞歸調用和引用計數巧妙的實現。
static void __clk_disable(struct clk *clk)
{
	if (clk == NULL || IS_ERR(clk))
		return;
	WARN_ON(!clk->usecount);
	if (!(--clk->usecount)) {
		if (clk->disable)
			clk->disable(clk);
		__clk_disable(clk->secondary);
		__clk_disable(clk->parent);
	}
}
static int __clk_enable(struct clk *clk)
{
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;
	if (clk->usecount++ == 0) {
		__clk_enable(clk->parent);
		__clk_enable(clk->secondary);
		if (clk->enable)
			clk->enable(clk);
	}
	return 0;
}
4. clk與pm
為了省電,當不需要clk時將其關閉,上面的clk_enable/clk_disable實現了此功能。除了關閉clk省電,還可以降低clk頻率以達到省電的目的。當系統當前負載較輕,不需要clk跑在那么高的頻率時,就可以對該clk降頻了。從這些關系可以看到,clk與電源管理,cpufreq等都可能有關聯。
mxc為各時鐘定義了幾個屬性標志:
arch/arm/plat-mxc/include/mach/clock.h
/* Clock flags */ #define RATE_PROPAGATES (1 << 0) /* Program children too */ #define ALWAYS_ENABLED (1 << 1) /* Clock cannot be disabled */ #define RATE_FIXED (1 << 2) /* Fixed clock rate */ #define CPU_FREQ_TRIG_UPDATE (1 << 3) /* CPUFREQ trig update */ #define AHB_HIGH_SET_POINT (1 << 4) /* Requires max AHB clock */ #define AHB_MED_SET_POINT (1 << 5) /* Requires med AHB clock */
總結
以上是生活随笔為你收集整理的linux clk时钟源管理的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: SAP Spartacus B2B 页面
- 下一篇: SAP Spartacus B2B 页面
