1. 程式人生 > >Exynos4412 中斷驅動開發(三)—— 裝置樹中中斷節點的建立

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

)這樣的片上匯流排連線到一個或者多個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 模型機添加了中斷連線:

[cpp] view plain copy

 

 在CODE上檢視程式碼片派生到我的程式碼片

  1. / {  
  2.   
  3.     compatible = "acme,coyotes-revenge";  
  4.     #address-cells = <1>;  
  5.     #size-cells = <1>;  
  6.     interrupt-parent = <&intc>;  
  7.   
  8.     cpus {  
  9.         #address-cells = <1>;  
  10.         #size-cells = <0>;  
  11.         [email protected] {  
  12.             compatible = "arm,cortex-a9";  
  13.             reg = <0>;  
  14.         };  
  15.   
  16.         [email protected] {  
  17.             compatible = "arm,cortex-a9";  
  18.             reg = <1>;  
  19.         };  
  20.     };  
  21.   
  22.     [email protected] {  
  23.         compatible = "arm,pl011";  
  24.         reg = <0x101f0000 0x1000 >;  
  25.         interrupts = < 1 0 >;  
  26.     };  
  27.   
  28.     [email protected] {  
  29.         compatible = "arm,pl011";  
  30.         reg = <0x101f2000 0x1000 >;  
  31.         interrupts = < 2 0 >;  
  32.     };  
  33.   
  34.     [email protected] {  
  35.         compatible = "arm,pl061";  
  36.         reg = <0x101f3000 0x1000  
  37.                0x101f4000 0x0010>;  
  38.         interrupts = < 3 0 >;  
  39.     };  
  40.   
  41.     intc: [email protected] {  
  42.         compatible = "arm,pl190";  
  43.         reg = <0x10140000 0x1000 >;  
  44.         interrupt-controller;                         //見上面,空的屬性,表明該節點是作為一個接收中斷的裝置
  45.         #interrupt-cells = <2>;  
  46.     };  
  47.   
  48.     [email protected] {  
  49.         compatible = "arm,pl022";  
  50.         reg = <0x10115000 0x1000 >;  
  51.         interrupts = < 4 0 >;  
  52.     };  
  53.   
  54. //external-bus的rangs屬性:
  55. //external-bus的ranges屬性定義了經過external-bus橋後的地址範圍如何對映到CPU的memory區域。看部落格sbh的詳細講解
  56.     external-bus {  
  57.         #address-cells = <2>  
  58.         #size-cells = <1>;  
  59.         ranges = <0 0  0x10100000   0x10000         // Chipselect 1, Ethernet  
  60.                      1 0  0x10160000   0x10000         // Chipselect 2, i2c controller  
  61.                      2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash  
  62. //解釋
  63. //ranges屬性為一個地址轉換表。表中的每一行都包含了子地址、父地址、在自地址空間內的區域大小。他們的大小(包含的cell)分別由子節點的address-

  64. //cells的值、父節點的address-cells的值和子節點

  65. //的size-cells來決定。以第一行為例:

  66. //0 0 兩個cell,由子節點external-bus的address-cells=<2>決定;
  67. //0x10100000 一個cell,由父節點的address-cells=<1>決定0x10000 一個cell,由子節點external-bus的size-cells=<1>決定。
  68. //最終第一行說明的意思就是:片選0 (注意有片選,這應該是外設的一個特點),偏移0(選中了網絡卡),被對映到CPU地址空間的0x10100000~0x10110000中,地址長度為0x10000。
  69.  
  70.   
  71.         [email protected],0 {  
  72.             compatible = "smc,smc91c111";  
  73.             reg = <0 0 0x1000>;  
  74.             interrupts = < 5 2 >;  
  75.         };  
  76.   
  77.         [email protected],0 {  
  78.             compatible = "acme,a1234-i2c-bus";  
  79.             #address-cells = <1>;  
  80.             #size-cells = <0>;  
  81.             reg = <1 0 0x1000>;  
  82.             interrupts = < 6 2 >;  
  83.   
  84.             [email protected] {  
  85.                 compatible = "maxim,ds1338";  
  86.                 reg = <58>;  
  87.                 interrupts = < 7 3 >;  
  88.             };  
  89.         };  
  90.   
  91.         [email protected],0 {  
  92.             compatible = "samsung,k8f1315ebm", "cfi-flash";  
  93.             reg = <2 0 0x4000000>;  
  94.         };  
  95.     };  
  96. };  

 

 

需要注意的事情:

■ 這個機器只有一箇中斷控制器:[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

 

 在CODE上檢視程式碼片派生到我的程式碼片

  1. #include "exynos4x12.dtsi"  
  2. /{        
  3.     compatible = "samsung,exynos4412";       
  4.     gic: [email protected] {        
  5.         cpu-offset = <0x4000>;   
  6.     };       
  7.   
  8.     [email protected] {              
  9.         samsung,combiner-nr = <20>;              
  10.         interrupts =    <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,                         
  11.                           <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,                         
  12.                               <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,                        
  13.                               <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>,                          
  14.                               <0 107 0>, <0 108 0>, <0 48 0>, <0 42 0>;       
  15.     };  
  16. };  

 

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

 

 

  1. fs4412-key{        
  2.     compatible = "fs4412,key";       
  3.     interrupt-parent = <&gpx1>;  
  4.     interrupts = <1 2>,<2 2>;  
  5. };