linux下基於vc088x開發板分析CLK模型(時鐘管理)
Linux clk 模型
Linux clk模型採用面向物件的思想來設計實現的。
在porting層建立一個一個的clk節點物件,然後將所有的clk節點物件連成一個list。
當驅動層需要設定時鐘的時候,通過porting層與驅動層直接的api函式進行操作。首先通過clk_get函式,根據clk節點的名字,獲取clk節點。然後,使用clk_set_rate()函式設定clk節點的時鐘。clk_set_rate() 函式最終將會呼叫clk節點物件的成員函式 clk->set_rate() 設定時鐘。
層次關係如下圖所示:
1. 驅動層與porting層之間的api
驅動層與porting層之間的api,定義在include/linux/clk.h檔案中
// clk的結構體,空的,
// 正真的實現在arch\arm\plat-vc088x\include\plat\clock.h
struct clk;
// 根據name獲得註冊過的clk
struct clk *clk_get(struct device *dev, constchar *id);
// 釋放clk
void clk_put(struct clk *clk);
//開啟和關閉clk
int clk_enable(struct clk *clk);
void clk_disable(struct clk *clk);
// 設定clk的頻率,獲得clk的頻率
int clk_set_rate(struct clk *clk, unsignedlong rate);
long clk_round_rate(struct clk *clk, unsignedlong rate); //無法設定精確clk
unsigned long clk_get_rate(struct clk*clk);
// 設定clk的parent,獲取clk的parent
int clk_set_parent(struct clk *clk, structclk *parent);
struct clk *clk_get_parent(struct clk*clk);
clk結構體,在arch\arm\plat-vc088x\include\plat\clock.h實現。
其它函式,在arch\arm\plat-vc088x\ clock.c 中實現,供驅動層模組呼叫。
2. clk porting層
2.1 clk porting 層包含3個檔案
clk porting 層主要包括3個檔案:
arch\arm\plat-vc088x\include\plat\clock.h // clk結構體的實現
arch\arm\plat-vc088x\clock.c // 驅動層與porting層之間的api的實現
arch\arm\mach-vc0882\clock-vortex.c // 建立clk 節點連結串列
2.2 clk的描述
在arch\arm\mach-vc0882\clock-vortex.c檔案中定義了下面這個陣列:
static struct clk* sys_clks[];
這個陣列使用struct clk結構體描述了所有的時鐘節點。
clk節點的資料結構,採用面向物件的思想。
下面以snr為例,介紹如何描述clk節點的。
static struct clk snr_clk = {
.name = "snr_clk", // 驅動層通過clk_get函式獲取clk使用
.flags = CLK_FLAG_DIV |CLK_FLAG_GATE | RECALC_ON_ENABLE,
.parent = &XCLK,
.max_dividor = 64,
.private_data =&snr_clkdata,
.enable = v8clk_clear_gatebit, // clk_enable 最終的實現程式碼
.disable = v8clk_set_gatebit, // clk_ disable 最終的實現程式碼
.recalc =vc88x_clk_recalc,
.set_rate = v8clk_setrate,// clk_ set_rate 最終的實現程式碼
.init = vc88x_clk_init,
};
static struct clk_data snr_clkdata = {
.clk_cfg_reg =V8REG_CLKRST_CIF_MCLK_CFG,
.cfg_data =&snr_clkcfg,
.cfg_mask = 0x3F00,
.pfnCfg =div_calculator,
.pfnRate = div_parser,
.clk_ctrl_reg =V8REG_CLKRST_CIF_MCLK_CTRL,
.gate_bit =(1<<1),
};
struct clk_data 這個結構體,用來儲存clk節點的暫存器以及相關的bit資訊的。這些成員變數在clk_set_rate、clk_enable、clk_ disable等api中被使用的。比較重要的,有如下成員變數:
clk_ctrl_reg
gate_bit
bypass_bit
clk_status_reg
clk_sw_rst_reg
clk_cfg_reg
div_max
div_min
div_shift
2.3 clk的註冊以及初始化過程
1.建立clk 節點list
2.初始化所有clk
在時鐘初始化的過程中,通過clk_register函式,將sys_clks陣列中所有的時鐘節點,都註冊到一個list中。函式呼叫過程如下:
->init_machine()(vortex_init ())
-> vc088x_register_baseclocks ()
-> clk_register ()
->list_add () // 建立clk 節點list
->clk->init(clk); // 這個時候會初始化clk
-> clk->set_rate()
3. 驅動程式如何使用clk模型的api
根據clk節點的name,通過clk_get 獲取時鐘節點。
clk1 = clk_get(&dev, " snr_clk");
clk2 = clk_get(&dev, " dpi_pixel_clk ");
clk3 = clk_get(&dev, " cvbs_pixel_clk ");
clk4= clk_get(&dev, " vdac_pixel_clk ");
……
然後,就可以通過驅動層與porting層之間的api來設定各個時鐘節點。
clk_disable(clk1);
clk_set_rate(clk2, 24*1000000);
clk_enable(clk3);
4. cpu切頻如何使用clk模型的api
cpu切頻驅動程式包括以下幾個檔案:
drivers\cpufreq\
cpufreq.c
cpufreq_conservative.c // 按次序切頻
cpufreq_ondemand.c // 按命令切頻
cpufreq_performance.c // 最高頻率
cpufreq_powersave.c // 最低頻率
cpufreq_stats.c
cpufreq_userspace.c
freq_table.c
cpu切頻 porting 層包括以下幾個檔案:
arch\arm\plat-vc088x\cpu.c // structcpufreq_driver 結構體
其中,cpufreq_driver 結構體的成員函式,基於linux clk 模型的驅動層和porting層的api來實現的。
static struct cpufreq_driver v8_driver = {
.flags = CPUFREQ_STICKY,
.verify = v8_verify_speed,
.target = v8_target, // 切頻最終呼叫的函式
.get = v8_getspeed,
.init = v8_cpu_init,
.exit = v8_cpu_exit,
.name = "v8cpu",
.attr = v8_cpufreq_attr,
};
v8_driver .target->
v8_target()
clk_set_rate(cpu_clk, freqs.new * 1000);
v8_driver .get->
v8_getspeed()
rate = clk_get_rate(cpu_clk) / 1000;