SoC中通常有很多IP,按邏輯可以把幾個相關功能的IP劃為一個電源域。一個電源域內的IP,通常按相同的方式由同一個硬件模塊PMIC供電,電壓一樣并且電源管理例如休眠喚醒一致。
為什么有設備電源管理還需要power domain劃分?
對每個設備電源管理太細化了,會造成額外的開銷。通常幾個設備可以一塊進行管理更加的方便,例如一個子系統,要么全工作要么全關閉,不會子系統內的某個設備單獨工作。這時候為了簡化管理工作就需要劃分出來一個domain。SOC上眾多電源域組成了一個電源域樹,他們之間存在著相互的約束關系,子電源域打開前,需要父電源域打開,父電源域下所有子電源域關閉,父電源域才能關閉。
Domain這個詞一般在權限管理中經常遇到,用于隔離,Domain內共進退。
雖然電源域的好處多多,卻不是越多越好,因為劃分電源域是需要成本的(需要在PMU中使用模擬電路完成,包括金錢成本和空間成本)。因此,大多數系統會根據功能,設置有限的幾個電源域,例如:CPU core(1、2、3…);GPU;NAND;DDR;USB;Display;Codec等等。
這種設計引出一個問題:存在多個模塊共用一個電源域的情況。因而要求在對模塊power on/off的時候,考慮power共用的情況:只要一個模塊工作,就要power on;直到所有模塊停止工作,才能power off。
1. 框架介紹
Kernel的PM domain framework(位于drivers/base/power/domain.c中),提供了管理和使用系統power domain的統一方法:
對底層power domain硬件的操作
對power domain hw的開啟操作,包括開鐘、上電、解復位、解除電源隔離等操作的功能封裝;
對power domain hw的關閉操作,包括關鐘、斷電、復位、做電源隔離等操作的功能封裝;
內部邏輯實現
通過dts描述power domain框架的設備節點,并描述每個power domain節點。提供出一個power domain framework的設備節點,及每個power domain子設備的節點,并指定power-domain-ccell = <1>,這樣可以通過power domain framework的設備及power domain的編號查找具體的power domain;
實現dts解析邏輯,獲取power domain的配置信息,并通過初始化函數對每個power domain進行初始化,所有的power domain統一的放在一個全局鏈表中,將power domain下所有的設備,放到其下的一個設備鏈表中;
為runtime pm、系統休眠喚醒等框架,注冊相應的回調函數,并實現具體的回調函數對應的power domain的開關函數;
上層使用power domain的上游驅動、框架及debug fs
linux系統的runtime power manager 框架通過提供runtime_pm_get_xxx/runtime_pm_put_xxx類接口給其他的drivers,對設備的開、關做引用計數,當引用計數從1->0時,會進一步調到power domain注冊的runtime_suspend回調,回調函數里會先調用設備的runtime_suspend回調,然后判斷power domain下的設備鏈表中所有的設備是否已經suspend,若已經suspend才真正關閉power domain。當引用計數從0->1時,會先調用到power domain使用的runtime_resume回調,回調函數里會先調用power domain的開啟操作,然后調用設備注冊的runtime_resume回調函數;
系統休眠喚醒在suspend_noirq/resume_noirq時會進行power domain的關閉與開啟的操作;
使用power domain的上游驅動:power domain內部ip的驅動。比如,dsp子系統power domain下面,有多個dsp核,每個dsp核對應一個power domain。這樣,每個dsp核設備驅動都要關聯到對應的dsp核power domain上,通過dsp核設備的dts里power-domains的屬性引用(power domain framework的節點引用及具體power domain的編號),將dsp核設備與相應的power domain關聯起來;
使用power domain的框架:runtime pm/系統休眠喚醒;
power domain也提供了一些debug fs文件節點供用戶debug使用,主要就是/sys/kernel/debug/pm_genpd/目錄及power domain名字目錄下的一些文件節點:
pm_genpd_summary:打印所有的power domain、狀態及下面所掛的設備狀態
power_domain名字目錄/current_state:power domain當前的狀態
power_domain名字目錄/sub_domains:power domain當前的子power domain有哪些
power_domain名字目錄/idle_states:power domain對應的所有idle狀態及其off狀態的時間
power_domain名字目錄/active_states:power domain處于on狀態的時間
power_domain名字目錄/total_idle_time:power domain所有idle狀態的off時間總和
power_domain名字目錄/devices:power domain下所掛的所有devices
相關數據結構:
image.png
初始化流程(以scmi power domain的驅動框架為例):
image.png
2. 如何使用power domain
在dts中定義一個power domain節點,同時在驅動中注冊該power domain即可
//DTS中定義powerdomain節點,這里以內核文檔提供的例程 parent:power-controller@12340000{ compatible="foo,power-controller"; reg=<0x12340000?0x1000>; #power-domain-cells=<1>;//這里表明parent節點是一個powerdomain,也就是內核文檔所形容的provider,parent管理它下面掛接著的其它模塊,為它們提供電源 }; child:power-controller@12341000{ compatible="foo,power-controller"; reg=<0x12341000?0x1000>; power-domains=<&parent?0>;//這里表明child節點是parent下面的一個模塊,它使用parent提供的電源 #power-domain-cells=<1>; };
從上面的dts語法中可以看出,一個系統的電源域從dts中可以很容易就看出來,#power-domain-cells聲明該節點是一個power domain,power-domains = <&xxx x>表明該節點屬于xxx電源域,那么系統中某個電源域下面有多少個模塊就從dts中看有多少個節點引用了該電源域即可。
3. provider
intpm_genpd_init(structgeneric_pm_domain*genpd, structdev_power_governor*gov,boolis_off)//初始化一個generic_pm_domain實例 //下面兩個接口都可以用來向內核注冊一個powerdomian intof_genpd_add_provider_onecell(structdevice_node*np, structgenpd_onecell_data*data) intof_genpd_add_provider_simple(structdevice_node*np, structgeneric_pm_domain*genpd)
pm_genpd_init這個函數從注釋可以看出它初始化了一個power domain實例,從入口參數結合具體的實現代碼,可以很容易得到 structgeneric_pm_domain結構體就對應著一個power domain實例。
structgeneric_pm_domain{ structdev_pm_domaindomain;/*PMdomainoperations*/ constchar*name; atomic_tsd_count;/*Numberofsubdomainswithpower"on"*/ enumgpd_statusstatus;/*Currentstateofthedomain*/ unsignedintdevice_count;/*Numberofdevices*/ unsignedintsuspended_count;/*Systemsuspenddevicecounter*/ unsignedintprepared_count;/*Suspendcounterofprepareddevices*/ int(*power_off)(structgeneric_pm_domain*domain);//驅動只要實現該函數即可 int(*power_on)(structgeneric_pm_domain*domain);//驅動只要實現該函數即可
真正需要驅動去賦值的成員只有兩個,那就是int (*power_off)(struct generic_pm_domain *domain); 與int (*power_on)(struct generic_pm_domain *domain);,其它的power domain framework已經幫我們做好了,這里我們也可以猜到一個電源域的打開與關閉最終是通過驅動注冊的這兩個函數操作的,
當驅動得到一個power domain實例后,便可以調用of_genpd_add_provider_simple函數向內核注冊一個power domain了,來進入該函數看看,做了哪些事情,看不太懂,但是從入口參數看,傳進去了驅動實現的struct generic_pm_domain和power domain的node節點。后續這兩個參數應該會有作用。
4. Consumer
Cousumer可能是一個驅動程序或者sysfs,在驅動probe函數中調用dev_pm_domain_attach
ret=dev_pm_domain_attach(_dev,true);//將設備與電源域進行耦合
驅動在probe的時候會調用dev_pm_domain_attach函數檢查設備是否屬于power domain設備,如果是,則獲取設備的power domain信息,從哪里獲取信息?就是從前面power domain驅動調用of_genpd_add_provider_simple函數注冊進來的信息。
調用genpd_add_device函數,將設備添加到該power domain中,主要完成一些struct generic_pm_domain成員的賦值操作。
最后最重要的就是調用dev_pm_domain_set該函數,設置了struct device中的struct dev_pm_domain成員,該成員被賦值為struct generic_pm_domain中的struct dev_pm_domain成員。
后記
power domain在底層的處理通常需要PPU硬件的參與管理,可以控制這個電源域的時鐘、電壓、供電等屬性,從而達到對電源和功耗的管理。
-
電源管理
+關注
關注
115文章
6154瀏覽量
144227 -
soc
+關注
關注
38文章
4118瀏覽量
217928 -
Power
+關注
關注
1文章
498瀏覽量
67694 -
PMIC
+關注
關注
15文章
312瀏覽量
109425
原文標題:參考:
文章出處:【微信號:OS與AUTOSAR研究,微信公眾號:OS與AUTOSAR研究】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論