Exynos4412 中斷驅動開發(三)—— 裝置樹中中斷節點的建立
https://www.cnblogs.com/tureno/articles/6403946.html
轉載於 : http://blog.csdn.net/zqixiao_09/article/details/50916212
題目: Exynos4412 中斷驅動開發(三)—— 裝置樹中中斷節點的建立
提到中斷就必須瞭解到GIC,下面先了解一下GIC
一、GIC概念
GIC(Generic Interrupt Controller)是ARM公司提供的一個通用的中斷控制器。GIC通過AMBA(Advanced Microcontroller Bus Architecture
下面是Exynos4412-fs4412 開發板(核心版本為 Linux 3.14)的中斷源連線:
二、裝置樹中中斷如何工作
與遵循樹的自然結構而進行的地址轉換不同,機器上的任何裝置都可以發起和終止中斷訊號。另外地址的編址也不同於中斷訊號,前者是裝置樹的自然表示,而後者者表現為獨立於裝置樹結構的節點之間的連結。描述中斷連線需要四個屬性:
■ interrupt-controller - 一個空的屬性定義(就是僅僅列出了該字串,見下面) , 該節點作為一個接收中斷訊號的裝置。
■ #interrupt-cells - 這是一箇中斷控制器節點的屬性。它聲明瞭該中斷控制器的中斷指示符中 cell 的個數(類似於 #address-cells 和 #size-cells)。
■ interrupt-parent - 這是一個裝置節點的屬性,包含一個指向該裝置連線的中斷控制器的 phandle。那些沒有 interrupt-parent 的節點則從它們的父節點中繼承該屬性。
■ interrupts - 一個裝置節點屬性,包含一箇中斷指示符的列表,對應於該裝置上的每個中斷輸出訊號。
中斷指示符是一個或多個 cell 的資料(由 #interrupt-cells 指定),這些資料指定了該裝置連線至哪些輸入中斷。在以下的例子中,大部分裝置都只有一個輸出中斷,但也有可能在一個裝置上有多個輸出中斷。一箇中斷指示符的意義完全取決於與中斷控制器裝置的 binding。每個中斷控制器可以決定使用幾個 cell 來唯一的定義一個輸入中斷。
下面的程式碼為我們 Coyote's Revenge 模型機添加了中斷連線:
[cpp] view plain copy
- / {
- compatible = "acme,coyotes-revenge";
- #address-cells = <1>;
- #size-cells = <1>;
- interrupt-parent = <&intc>;
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
- [email protected] {
- compatible = "arm,cortex-a9";
- reg = <0>;
- };
- [email protected] {
- compatible = "arm,cortex-a9";
- reg = <1>;
- };
- };
- [email protected] {
- compatible = "arm,pl011";
- reg = <0x101f0000 0x1000 >;
- interrupts = < 1 0 >;
- };
- [email protected] {
- compatible = "arm,pl011";
- reg = <0x101f2000 0x1000 >;
- interrupts = < 2 0 >;
- };
- [email protected] {
- compatible = "arm,pl061";
- reg = <0x101f3000 0x1000
- 0x101f4000 0x0010>;
- interrupts = < 3 0 >;
- };
- intc: [email protected] {
- compatible = "arm,pl190";
- reg = <0x10140000 0x1000 >;
- interrupt-controller; //見上面,空的屬性,表明該節點是作為一個接收中斷的裝置
- #interrupt-cells = <2>;
- };
- [email protected] {
- compatible = "arm,pl022";
- reg = <0x10115000 0x1000 >;
- interrupts = < 4 0 >;
- };
- //external-bus的rangs屬性:
- //external-bus的ranges屬性定義了經過external-bus橋後的地址範圍如何對映到CPU的memory區域。看部落格sbh的詳細講解
- external-bus {
- #address-cells = <2>
- #size-cells = <1>;
- ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
- 1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
- 2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
- //解釋
-
//ranges屬性為一個地址轉換表。表中的每一行都包含了子地址、父地址、在自地址空間內的區域大小。他們的大小(包含的cell)分別由子節點的address-
-
//cells的值、父節點的address-cells的值和子節點
-
//的size-cells來決定。以第一行為例:
- //0 0 兩個cell,由子節點external-bus的address-cells=<2>決定;
- //0x10100000 一個cell,由父節點的address-cells=<1>決定0x10000 一個cell,由子節點external-bus的size-cells=<1>決定。
- //最終第一行說明的意思就是:片選0 (注意有片選,這應該是外設的一個特點),偏移0(選中了網絡卡),被對映到CPU地址空間的0x10100000~0x10110000中,地址長度為0x10000。
- [email protected],0 {
- compatible = "smc,smc91c111";
- reg = <0 0 0x1000>;
- interrupts = < 5 2 >;
- };
- [email protected],0 {
- compatible = "acme,a1234-i2c-bus";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1 0 0x1000>;
- interrupts = < 6 2 >;
- [email protected] {
- compatible = "maxim,ds1338";
- reg = <58>;
- interrupts = < 7 3 >;
- };
- };
- [email protected],0 {
- compatible = "samsung,k8f1315ebm", "cfi-flash";
- reg = <2 0 0x4000000>;
- };
- };
- };
需要注意的事情:
■ 這個機器只有一箇中斷控制器:[email protected]。
■ 中斷控制器節點上添加了‘inc:’標籤,該標籤用於給根節點的 interrupt-parent 屬性分配一個 phandle。這個 interrupt-parent 將成為本系統的預設值,因為所有的子節點都將繼承它,除非顯示覆寫這個屬性。
■ 每個裝置使用 interrupts 屬性來不同的中斷輸入線。
■ #interrupt-cells 是 2,所以每個中斷指示符都有 2 個 cell。本例使用一種通用的模式,也就是用第一個 cell 來編碼中斷線號;然後用第二個 cell 編碼標誌位,比如高電平/低電平有效,或者邊緣/水平觸發。對於任何給定的中斷控制器,請參考該控制器的 binding 文件以瞭解指示符如何編碼。
三、GIC DTS描述
1、中斷系統概述
對於中斷系統,主要有三個角色:
(1)processor:主要用於處理中斷;
(2)Interrupt Generating Device:通過硬體的interrupt line表明自身需要處理器的進一步處理(例如有資料到來、異常狀態等)
(3)interrupt controller:負責收集各個外設的非同步事件,用有序、可控的方式通知一個或者多個processor。
2、DTS如何描述Interrupt Generating Device
對於Interrupt Generating Device,我們需要定義下面兩個屬性:
(1) Interrupt屬性:該屬性主要描述了中斷的HW interrupt ID以及型別。
(2)interrupt-parent 屬性:該屬性主要描述了該裝置的interrupt request line連線到哪一個interrupt controller。
我們以一個簡單的串列埠為例子,
uart3: [email protected] {
compatible = "ti,omap4-uart";
reg = <0x48020000 0x100="">;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart3";
clock-frequency = <48000000>;
};
對於uart3,interrupts屬性用3個cell(對於device tree,cell是指由32bit組成的一個資訊單位)表示。GIC_SPI 描述了interrupt type。
對於GIC,它可以管理4種類型的中斷:
1)外設中斷(Peripheral interrupt)
根據目標CPU的不同,外設的中斷可以分成PPI(Private Peripheral Interrupt)和SPI(Shared Peripheral Interrupt)。PPI只能分配給一個確定的processor,而SPI可以由Distributor將中斷分配給一組Processor中的一個進行處理。外設型別的中斷一般通過一個interrupt request line的硬體訊號線連線到中斷控制器,可能是電平觸發的(Level-sensitive),也可能是邊緣觸發的(Edge-triggered)。
2)軟體觸發的中斷(SGI,Software-generated interrupt)
軟體可以通過寫GICD_SGIR暫存器來觸發一箇中斷事件,這樣的中斷,可以用於processor之間的通訊。
3)虛擬中斷(Virtual interrupt)和 Maintenance interrupt。
這兩種中斷和本文無關,不再贅述。
在DTS中,外設的interrupt type有兩種,一種是SPI,另外一種是PPI。SGI用於processor之間的通訊,和外設無關。 uart3的interrupt屬性中的74表示該外設使用的GIC interrupt ID號。GIC最大支援1020個HW interrupt ID,具體的ID分配情況如下:1)ID0~ID31是用於分發到一個特定的process的interrupt。標識這些interrupt不能僅僅依靠ID,因為各個interrupt source都用同樣的ID0~ID31來標識,因此識別這些interrupt需要interrupt ID + CPU interface number。ID0~ID15用於SGI,ID16~ID31用於PPI。PPI型別的中斷會送到指定的process上,和其他的process無關。SGI是通過寫GICD_SGIR暫存器而觸發的中斷。Distributor通過processor source ID、中斷ID和target processor ID來唯一識別一個SGI。2)ID32~ID1019用於SPI。uart3的interrupt屬性中的IRQ_TYPE_LEVEL_HIGH用來描述觸發型別。
3、DTS如何描述GIC
linux-3.14\arch\arm\boot\dts\exynos4412.dtsi檔案中
[java] view plain copy
- #include "exynos4x12.dtsi"
- /{
- compatible = "samsung,exynos4412";
- gic: [email protected] {
- cpu-offset = <0x4000>;
- };
- [email protected] {
- samsung,combiner-nr = <20>;
- interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
- <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
- <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
- <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>,
- <0 107 0>, <0 108 0>, <0 48 0>, <0 42 0>;
- };
- };
a -- compatible屬性
compatible屬性用來描述GIC的programming model。該屬性的值是string list,定義了一系列的modle(每個string是一個model)。這些字串列表被作業系統用來選擇用哪一個driver來驅動該裝置。
假設定義該屬性:compatible = “a廠商,p產品”, “標準bbb型別裝置”。那麼linux kernel可能首先使用“a廠商,p產品”來匹配適合的driver,如果沒有匹配到,那麼使用字串“標準bbb型別裝置”來繼續尋找適合的driver。
compatible屬性有兩個應用場景:
1)對於root node,compatible屬性是用來匹配machine type的(參考Device Tree相關文件)
2)對於普通的HW block的節點(硬體模組節點如中斷控制器),例如interrupt-controller,compatible屬性是用來匹配適合的driver的。
b -- interrupt-controller
interrupt-controller這個沒有定義value的屬性用來表明本裝置節點就是一個interrupt controller。理解#interrupt-cells這個屬性需要理解interrupt specifier和interrupt domain這兩個概念。interrupt specifier其實就是外設interrupt的屬性值,對於uart3而言,其interrupt specifier就是<GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,也就是說,interrupt specifier定義了一個外設產生中斷的規格(HW interrupt ID + interrupt type)。
具體如何解析interrupt specifier?這個需要限定在一定的上下文中,不同的interrupt controller會有不同的解釋。因此,對於一個包含多個interrupt controller的系統,每個interrupt controller及其相連的外設組成一個interrupt domain,各個外設的interrupt specifier只能在屬於它的那個interrupt domain中得到解析。#interrupt-cells定義了在該interrupt domain中,用多少個cell來描述一個外設的interrupt specifier。
c -- reg
reg屬性定義了GIC的memory map的地址.
三、GIC的HW block diagram描述
1、Distributor
Distributor的主要的作用是檢測各個interrupt source的狀態,控制各個interrupt source的行為,分發各個interrupt source產生的中斷事件到各個processor。
Distributor對中斷的控制包括:
1)中斷enable或者disable的控制。Distributor對中斷的控制分成兩個級別。一個是全域性中斷的控制。一旦disable了全域性的中斷,那麼任何的interrupt source產生的interrupt event都不會被傳遞到CPU interface。另外一個級別是對針對各個interrupt source進行控制,disable某一個interrupt source會導致該interrupt event不會分發到CPU interface,但不影響其他interrupt source產生interrupt event的分發。
2)控制中斷事件分發到processor。一個interrupt事件可以分發給一個processor,也可以分發給若干個processor。
3)優先順序控制。
4)interrupt屬性設定。例如是level-sensitive還是edge-triggered,是屬於group 0還是group 1。
Distributor可以管理若干個interrupt source,這些interrupt source用ID來標識,我們稱之interrupt ID。
2、CPU interface
CPU interface這個block主要用於和processor進行介面。該block的主要功能包括:
1)enable或者disable
對於ARM,CPU interface block和processor之間的中斷訊號線是nIRQ和nFIQ這兩個signal。如果disable了中斷,那麼即便是Distributor分發了一箇中斷事件到CPU interface,但是也不會assert指定的nIRQ或者nFIQ通知processor。
2)ackowledging中斷
processor會向CPU interface block應答中斷,中斷一旦被應答,Distributor就會把該中斷的狀態從pending狀態修改成active。如果沒有後續pending的中斷,那麼CPU interface就會deassert nIRQ或者nFIQ的signal。如果在這個過程中又產生了新的中斷,那麼Distributor就會把該中斷的狀態從pending狀態修改成pending and active。這時候,CPU interface仍然會保持nIRQ或者nFIQ訊號的asserted狀態,也就是向processor signal下一個中斷。
3)中斷處理完畢的通知
當interrupt handler處理完了一箇中斷的時候,會向寫CPU interface的暫存器從而通知GIC CPU已經處理完該中斷。做這個動作一方面是通知Distributor將中斷狀態修改為deactive,另外一方面,如果一箇中斷沒有完成處理,那麼後續比該中斷優先順序低的中斷不會assert到processor。一旦標記中斷處理完成,被block掉的那些比當前優先順序低的中斷就會遞交給processor。
4)設定priority mask
通過priority mask,可以mask掉一些優先順序比較低的中斷,這些中斷不會通知到CPU。
5)設定preemption的策略
6)在多箇中斷事件同時到來的時候,選擇一個優先順序最高的通知processor
四、本次按鍵中斷節點填寫
1、檢視原理圖
2、可以看到中斷 EINT9 EINT10 掛在GPX1下 1 2
3、檢視中斷號
4、確定其父節點
5、確定中斷節點
[java] view plain copy
- fs4412-key{
- compatible = "fs4412,key";
- interrupt-parent = <&gpx1>;
- interrupts = <1 2>,<2 2>;
- };