linux设备驱动程序之时钟管理
???? 時鐘管理模塊是linux系統為統一管理各硬件的時鐘而實現管理框架,負責所有模塊的時鐘調節和電源管理。時鐘管理模塊主要負責處理各硬件模塊的工作頻率調節及電源切換管理。一個硬件模塊要正常工作,必須先配置好硬件的工作頻率、打開電源開關、總線訪問開關等操作,時鐘管理模塊為設備驅動提供統一的操作接口,使驅動不用關心時鐘硬件實現的具體細節
1.系統時鐘結構
系統時鐘主要是指一些源時鐘,為其它硬件模塊提供時鐘源輸入。系統時鐘一般為多個硬件模塊共享,不允許隨意調節。
系統上一般只有兩個時源頭:低頻晶振(LOSC)32Khz和高頻晶振(HOSC)24Mhz,系統在HOSC的基礎上,增加一些鎖相環電路,實現更高的時鐘頻率輸出。為了便于控制一些模塊的時鐘頻率,系統對時鐘源進行了分組,實現較多的鎖相環電路,以實現分路獨立調節。
由于CPU、總線的時鐘比較特殊,其工作時鐘也經常會輸出作為某些其它模塊的時鐘源,因此,我們也將此類時鐘歸結為系統時鐘。其結構圖如下:
各PLL的分工如下:
pll_cpu只作為CPU的時鐘源,不作他用;
pll_audio只作為音頻模塊(如codec、iis、spdif等)的時鐘源,不作他用;
pll_video0、pll_video1一般作為顯示相關模塊(如de、csi、hdmi等)的時鐘源;
pll_ve一般只作為視頻解碼模塊(ve)的時鐘源;
pll_ddr0、pll_ddr1一般只作為DDR的時鐘源;
hosc用作一些外設接口模塊(如nand、sdmmc、usb等)的時鐘源;
pll_gpu一般只作為GPU模塊的時鐘源;
pll_periph0、pll_periph1是兩個通用時鐘源,可以為多個模塊共享
2.模塊時鐘結構
???? 模塊時鐘主要是針對一些具體模塊(如:gpu、de),在時鐘頻率配置、電源控制、訪問控制等方面進行管理。一個典型的模塊如下圖所示,包含module gateing、ahb gating、dram gating,以及reset控制。要想一個模塊能夠正常工作,必須在這幾個方面作好相關的配置。
硬件設計時,為每個硬件模塊定義好了可選的時鐘源(有些默認使用總線的工作時鐘作時鐘源),時鐘源的定義如上節所述,模塊只能在相關可能的時鐘源間作選擇。
模塊的電源管理體現在兩個方面:模塊的時鐘使能和模塊控制器復位,相關驅動需要通過以下所列的時鐘進行控制。
CCU的源碼結構如下圖所示:
|---drivers
||---clk
|||---xxx
||||---clk-xxx.h
||||---clk-periph.h
||||---clk-sunxi.h
||||---clk-factors.h
||||---clk-factors.c
||||---clk-periph.c
||||---clk-xxx.c
||||---clk-default.c
||||---clk-xxx_tbl.c
||||---clk-debugfs.c
|---include
||---linux
|||---clk.h
|||---clk
|
|
clk.h 時鐘子系統提供的API接口定義;
clk-factors.c: 針對PLLx等系統時鐘(以HOSC為source)的公用代碼
clk-periph.c:針對各模塊時鐘的公用代碼
clk-xxx.c:針對xxx的實現
clk-default.c: 第二級初始化操作
clk-debugfs.c: 針對debugfs的調試接口
clk-xxx_tbl.c:針對xxx平臺clk table
3.使用方法
(1) 一定要判斷clk_get返回句柄的有效性.比如:
規范寫法:
| struct clk *pll = clk_get(NULL, "sys_pll3"); if(!pll || IS_ERR(pll)){ ?????? /* 獲取時鐘句柄失敗 */ ?????? printk(“try to get pll3 failed!\n”); } ... |
|
|
(2) 有返回值的clk api一定要判斷返回值,返回失敗時建議加打印,比如:
規范寫法:
| if(clk_enable(pll)) { ?????? /* 使能 PLL3輸出失敗 */ ?????? printk("try to enable pll3 output failed!\n"); } |
(3) clk_disable或clk_put之前,先檢查句柄的有效性;clk_put之后將句柄清空.比如:
| if(NULL == sdc0_clk || IS_ERR(sdc0_clk)){ ?????? printk("sdc0_clk handle is invalid, just return!\n"); ?????? return; } else { ?????? clk_disable(sdc0_clk); ?????? clk_put(sdc0_clk); ?????? sdc0_clk = NULL; } |
(4)設置PLL3頻率
| struct clk *pll = clk_get(NULL, "sys_pll3"); if(!pll || IS_ERR(pll)){ ?????? /* 獲取時鐘句柄失敗 */ ?????? printk(“try to get pll3 failed!\n”); } /* 使能時鐘 */ if(clk_prepare_enable(pll)) { ?????? /* 使能 PLL3輸出失敗 */ ?????? printk("try to enable pll3 output failed!\n"); } /* 設置 PLL3的頻率為270Mhz */ if(clk_set_rate(pll, 270000000)) { ?????? /* 設置 PLL3頻率失敗 */ ?????? printk("try to set rate to 270000000 failed!\n"); } |
總結
以上是生活随笔為你收集整理的linux设备驱动程序之时钟管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue created 生命周期
- 下一篇: linux中文变成日文,linux nk