linux clk時鍾源管理


硬件資源越來越龐大和復雜,內核的另一個挑戰就是要便捷的管理這些資源。同時,面對如此之多的平台不同的CPU,管理機制需要統一適用,這就需要對資源的管理抽象到更加通用的層次。CPU中各個模塊都需要時鍾驅動,內核需要一種機制能通用所有的平台,方便的管理CPU上所有的clk資源。這里分析Linux對clk的管理。
Linux version: 2.6.38
平台: i.mx53 (mxc),以下所有平台相關部分都特指i.mx53
涉及的源文件有:
  • include/linux/clk.h
  • drivers/clk/clkdev.c
  • arch/arm/plat-mxc/clock.c
  • arch/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 */



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM