轉載於 : http://blog.csdn.net/zqixiao_09/article/details/50916212
題目: Exynos4412 中斷驅動開發(三)—— 設備樹中中斷節點的創建
提到中斷就必須了解到GIC,下面先了解一下GIC
一、GIC概念
GIC(Generic Interrupt Controller)是ARM公司提供的一個通用的中斷控制器。GIC通過AMBA(Advanced Microcontroller Bus Architecture)這樣的片上總線連接到一個或者多個ARM processor上。
下面是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 模型機添加了中斷連接:
- / {
- compatible = "acme,coyotes-revenge";
- #address-cells = <1>;
- #size-cells = <1>;
- interrupt-parent = <&intc>;
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
- cpu@0 {
- compatible = "arm,cortex-a9";
- reg = <0>;
- };
- cpu@1 {
- compatible = "arm,cortex-a9";
- reg = <1>;
- };
- };
- serial@101f0000 {
- compatible = "arm,pl011";
- reg = <0x101f0000 0x1000 >;
- interrupts = < 1 0 >;
- };
- serial@101f2000 {
- compatible = "arm,pl011";
- reg = <0x101f2000 0x1000 >;
- interrupts = < 2 0 >;
- };
- gpio@101f3000 {
- compatible = "arm,pl061";
- reg = <0x101f3000 0x1000
- 0x101f4000 0x0010>;
- interrupts = < 3 0 >;
- };
- intc: interrupt-controller@10140000 {
- compatible = "arm,pl190";
- reg = <0x10140000 0x1000 >;
- interrupt-controller; //見上面,空的屬性,表明該節點是作為一個接收中斷的設備
- #interrupt-cells = <2>;
- };
- spi@10115000 {
- 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。
- ethernet@0,0 {
- compatible = "smc,smc91c111";
- reg = <0 0 0x1000>;
- interrupts = < 5 2 >;
- };
- i2c@1,0 {
- compatible = "acme,a1234-i2c-bus";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1 0 0x1000>;
- interrupts = < 6 2 >;
- rtc@58 {
- compatible = "maxim,ds1338";
- reg = <58>;
- interrupts = < 7 3 >;
- };
- };
- flash@2,0 {
- compatible = "samsung,k8f1315ebm", "cfi-flash";
- reg = <2 0 0x4000000>;
- };
- };
- };
需要注意的事情:
■ 這個機器只有一個中斷控制器:interrupt-controller@10140000。
■ 中斷控制器節點上添加了‘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。
我們以一個簡單的串口為例子,
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文件中
- #include "exynos4x12.dtsi"
- /{
- compatible = "samsung,exynos4412";
- gic: interrupt-controller@10490000 {
- cpu-offset = <0x4000>;
- };
- interrupt-controller@10440000 {
- 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、確定中斷節點