'디바이스트리'에 해당되는 글 2건

  1. 2015.03.24 디바이스 트리 작성법 (3편)
  2. 2015.03.24 디바이스 트리 작성법 (2편) (1)
2015.03.24 15:00


디바이스 트리 작성법 (3편)

4.  인터럽트 처리 방법

디바이스 트리 구조내에서 디바이스들은 트리 구조로 계층화 표현이 가능합니다. 
인터럽트는 이런 계층 구조가 곤란 합니다. 
보통 인터럽트는 디바이스의 하드웨어가 인터럽트를 발생하고 
인터럽트 컨트롤러가 해당 신호를 수신하는 구조로 되어 있습니다. 
그래서 인터럽트는 디바이스 트리의 구조와 별도로 디바이스 노드간에 링크 구조로 표현됩니다. 
인터럽트는 디바이스 노드의 속성의 형태로 표현합니다. 
네개의 속성이 인터럽트 간의 연결을 표현하기 위해서 준비 되어 있습니다.
다음은  네개의 속성에 대한 간단한 설명입니다. 
- interrupt-controller 속성
interrupt-controller 속성 은 값이 없는 빈 속성으로 해당 노드의 디바이스가 
인터럽트 신호를 수신하는 인터럽트 컨트롤러 디바이스 임을 표현합니다. 

- interrupt-parent
interrupt-parent 속성을 통해서 라벨 참조 형태로 지정하는 디바이스를 
디바이스 트리의 계층 구조에서 
가장 상위의 인터럽트 컨트롤러로 정의 하게 됩니다. 
interrupt-parent 속성을 갖지 않은 노드들은 그들의 부모 노드중 
interrupt-parent 속성이 선언된 노드의 interrupt-parent 속성을 상속 받습니다. 
- #interrupt-cells 속성
#interrupt-cells 속성에 지정된 값은 interrupts 속성에서 인터럽트에 대한 정보를 속성값으로 표현할때 
사용될 셀수를 나타냅니다. ( #address-cells 와 #size-cells 과 비슷한 역활을 합니다.  )
interrupt-controller 속성이 선언된 노드에 같이 선언됩니다. 
- interrupts 
interrupts  속성은 디바이스가 발생하는 인터럽트 출력 신호에 대한 정보의 리스트를 값으로 표현합니다. 
interrupts 의 속성에 표현되는 한개의 인터럽트에 대한 정보는 여러개의 셀로 구성됩니다. 
이 인터럽트는 인터럽트 컨트롤러에 연결된 인터럽트 입력에 정보 입니다. 
아래 예에 보듯이 대부분의 디바이스는 보통 하나의 인터럽트 출력만 있습니다. 
그러나 어떤 디바이스는 여러개의 인터럽트 출력이 있을 수 있습니다. 
interrupts 의 속성 값에 지정되는 정보의 의미는 인터럽트 컨트롤러에 의존적입니다. 
인터럽트 콘트롤러 마다 인터럽트를 다루기 위한 나름대로의 특성이 있으므로 이에 맞는 것으로 정의하고 
이에 따라서 셀수가 결정됩니다. 

아래 코드는 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 {
#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
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 로 지정된 한개의 인터럽트 컨트롤러를 가지고 있다. 

여기서 특이하게 'intc:' 라고 하는 라벨이 인터럽트 컨트롤러 노드에 추가된 것을 볼 수 있습니다. 
이 라벨은 루트 노드에 interrupt-parent 속성에서 사용합니다. 
interrupt-parent = <&intc>;
이 interrupt-parent 속성 값은 시스템의 디폴트 인터럽트 컨트롤러를 지정합니다. 
자식 노드들은 해당 인터럽트를 수신하는 것이 어떤 것인가를 지정하지 않고 
상위 노드에서 interrupt-parent 속성으로 지정된 인터럽트 컨트롤러를 해당 디바이스 노드에 연결된 
인터럽트 컨트롤러를 디폴트로 지정합니다. 
왜냐하면 모든 자식 노드들은 해당 속성을 쓰지 않아도 상위 노드에 지정된  interrupt-parent 속성이 상속되기 때문이다. 
각 디바이스의 interrupts 속성은 각각의 인터럽트 입력 라인을 기술하기 위해서 사용합니다.
이때 인터럽트 컨트롤러를 표현한 노드에 정의된 #interrupt-cells 속성은 
interrupts 속성에서 하나의 인터럽트에 대한 기술을 하기 위한 셀 수를 지정합니다. 
위 예에서 "#interrupt-cells" 은 2 입니다. 그래서 하나의 인터럽트 입력을 표현하기 위해서는 2 개의 셀이 필요합니다. 
이 예에서는 인터럽트 라인 번호를 표현하기 위해서 첫번째 셀이 쓰입니다. 
그리고 두번째 셀은 액티브 되는 인터럽트 레벨의 조건이 레벨 하이인지 로우인지 엣지인지를 나타냅니다. 
여러분이 다루고자 하는 인터럽트 컨트롤러에 인터럽트 입력에 대한 부분을 다루고자 한다면 
해당 인터럽트 컨트롤러의 매뉴얼을 참조해야 합니다. 
5.  디바이스 표현 데이터

지금까지 다룬 공통된 속성이외에, 여러분이 필요하다고 생각되는 임의의 속성이나 자식 노드들을 
노드에 포함시킬 수 있습니다. 
만약에 디바이스 트리에 여러분이 다루는 운영체제에서 필요로 하는 어떤 데이터를 추가 하고 싶다면
다음과 같은 규칙 하에 추가 하시기 바랍니다. 
첫째, 새로운 디바이스 노드에 추가할 속성 이름은 표준 속성 이름과 충돌을 방지하기 위해서 제조사 접두사를 붙이싶시오.
두번째, 속성의 의미와 자식 노드에 대한 것은 
운영체제의 디바이스 드라이버 개발자가 해당 내용을 이해할 수 있도록 바인딩 문서에 문서화 하시기 바랍니다. 
여기서 디바이스 트리에서 바인딩이라고 하는 의미는 
디바이스 트리 안에서 디바이스가 표현되는 것을 의미합니다. 
바인딩관 관련되어 기술되는 문서에는 해당 디바이스 노드에 
새로 만들어지는 속성은 어떤 의미인지, 속성은 어떤 값을 갖을 수 있는지 , 자식 노드를 가지고 있는지, 
기술하고자 하는 디바이스가 어떤 디바이스인지가 표현되어야 합니다. 
디바이스를 표현하는 노드 각각은 compatible 속성 값에 각각이 서로 구별될 수 있는 고유의 문자열을 사용하여야 합니다. 
새로운 디바이스들에 대한 바인딩은 이 문서가 있는 사이트의 위키에 문서화 되어야 합니다.
문서 형식과 검토 프로세스에 대해서 설명하는 메인 페이지를 보시기 바랍니다 
세번째, devicetree-discuss@lists.ozlabs.org 메일링 리스트에 새로 만들어진 바인딩과 관련된 검토 내용을 
        포스팅하시기 바랍니다.
포스팅을 하시면 나중에 발생할 수 있는 많은 예상되는 문제들 중 공통된 실수를 잡을 수 있습니다. 

6.  특별한 노드들 

6.1 aliases 노드

어떤 노드는 노드 이름으로 /external-bus/ethernet@0,0 와 같이 풀 패쓰 즉 긴 이름을 사용합니다. 
또는 우리는 이런 긴 이름보다는 eth0  와 같은 짧은 이름을 종종 사용합니다. 
그래서 디바이스 트리를 볼 때 "eth0 가 무슨 디바이스일까?" 라는 생각으로 보게 됩니다 .
이런 경우들에 대해서 디바이스 트리는 aliases 라는 노드를 제공하여 
쉽게 긴이름을 짧은 이름으로 대치하게 하거나 일반적으로 알수 있는 용어로 바꾸어 사용할 수 있도록 
해 줍니다. 
예를 들면:

aliases {
ethernet0 = &eth0;
serial0 = &serial0;
};
즉 ethernet0 는 eth0 라는 이름과 같다는 것을 표현해 줄 수 있습니다. 

aliases 안에 기술되는 형식은 

별명  = &라벨;
형태가 됩니다. 

이런 문법 표현은 별명에 해당하는 문자열을 라벨에 대한 참조로 사용할 수 있도록 합니다. 
이런 표현은 운영체제가 디바이스 의 식별자를 부여하는 방법으로 환영할 만한 것입니다. 

그리고 위 표현 방법은 의미는 interrupt-parent 속성 값을 표현 할때 사용했던 "< &label >" 와는 다른 것임을 주의 하십시오. 
6.2 chosen 노드

chosen 노드는 실제 디바이스를 디바이스 트리에 표현하는 것은 아닙니다 .

단지, 부트 아큐먼트와 같은, 펌웨어에서 운영 체제에 전달된 데이터를 파씽하기 위한 방법으로 제공됩니다.
일반적으로 .dts 소스 파일들내에 기술된 chosen 노드는 왼쪽 키 부분이 비어 있습니다. 
         그리고 그 정보는 부팅 동안만 유효합니다.
예제 시스템에서, 펌웨어는 chosen 노드를 다음과 같이 추가 하도록 하겠습니다.

chosen {
bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};


신고

'Computer > Linux/Unix' 카테고리의 다른 글

[Kernel Macro] container_of 매크로  (0) 2015.03.26
디바이스 트리 작성법 (4편)  (0) 2015.03.24
디바이스 트리 작성법 (3편)  (0) 2015.03.24
디바이스 트리 작성법 (2편)  (1) 2015.03.24
디바이스 트리 작성법 (1편)  (0) 2015.03.24
[Linux] Module 관련  (0) 2015.03.13


Posted by injunech
2015.03.24 14:59


디바이스 트리 작성법 (2편)

3 주소지정 방법
디바이스의 주소를 디바이스 트리에 표현하기 위해서 정해진 속성에는 다음 세가지가 있습니다. 

#address-cells
#size-cells
reg
이 속성은 서로 연관 관계를 가지고 있습니다. 
"#address-cells" 속성과 "#size-cells" 속성은 reg 속성의데이터에 대한 갯수 규칙을 지정합니다. 
"#address-cells" 속성과 "#size-cells" 은 부모 노드에서 지정하고 
reg 속성 은 자식 노드에 지정합니다. 
우선 reg 속성에 대해서 알아 보겠습니다. 
reg 속성은 다음과 같은 형식을 가집니다. 
"reg = <주소1 길이1 [주소2 길이2] [주소3 길이3] ... >"
주소와 길이가 하나의 묶음이 됩니다. 
보드에 있는 디바이스를 제어하기 위해서 하나의 주소일수도 있고 여러개의 주소를 가지고 있을 수 있습니다. 
또 각 주소는 연속적일 수도 있고 불연속 적일 수 도 있습니다. 
그래서 시작주소와 시작주소부터의 주소 범위를 하나의 묶음으로 지정하고 이것을 나열하게 됩니다. 
여기서 우선 셀(cell) 이라는 용어에 대해서 알아 보겠습니다. 
주소나 길이를 나타내기 위해서는 32비트 정수값을 사용합니다. 
예를 들면 0x12345678 또는 0 처럼 표현할 수 있습니다. 
이런 값 하나를 셀이라고 합니다. 
결론적으로 셀은 32비트 정수값이라고 보시면 됩니다. 
reg 는 다음과 같이 셀들의 데이터 집합으로 표현합니다.
reg = <0x0C00 0x0 0xFFFF02 0x3333>
여기서 0x0C00 0x0 0xFFFF02 0x3333 이 셀들입니다. 
그런데 여러분은 이 값들의 의미가 이런 식으로 될것이라고 예상 할 수 있을 겁니다. 
0x0C00  : 시작 주소 , 0x0  : 주소 범위 크기 
0xFFFF02 : 시작 주소 , 0x3333 : 주소 범위 크기 
예.. 이렇게 생각하면 맞을 수 도 있고 틀릴수도 있습니다. 
만약에 64비트 주소 체계라면 어떻게 하시겠습니까?
아니면 특수한 주소라서 32비트로 모두 표현할수 없다면?
이런 문제를 해결하기 위해서 
"#address-cells" 속성과 "#size-cells" 속성이 있는 겁니다. 
보통 다음과 같이 reg 의 셀들이 주소를 지정하기 위해서 몇개의 셀을 사용할지를 결정하고 
길이를 지정하기 위해서 몇개의 셀들을 사용할지를 결정해 주는 것이 바로 
"#address-cells" 속성과 "#size-cells" 속성입니다. 
이름 처럼 
#address-cells 속성은 reg 속성 값에 시작 주소를 지정하기 위해서 몇개의 셀을 사용할 것인가를 지정합니다. 
#size-cells 속성은 reg 속성 값에 길이를 지정하기 이해서 몇개의 셀을 사용할 것인가를 지정합니다. 
개념 설명을 하기 위해서 시작 주소는 2개의 셀을 가지고 길이는 1개의 셀을 가질 경우에 대한 예를 보여 드리겠습니다. 
실제 사용 방법은 CPU 와 디바이스를 추가 할때 다시 설명할 것입니다. 
parent {
#address-cells = <2>;
#size-cells = <1>;
child {
:
reg = <0xC0000000 0x0000 1024>;
};
child {
:
reg = <0xD0000000 0x0000 1024 0xE0000000 0x0000 2048>;
};
};
샘플 예를 보시면 아시겠지만 
#address-cells  속성과 #size-cells 은 자식 노드에만 영향을 줍니다. 
자신에 대한 셀 에 대한 지정은 상위 노드에서 지정해야 합니다. 
이제 주소 지정과 관련하여 CPU 부터 디바이스 까지 살펴 보겠습니다. 

3.1 CPU 주소 지정

보통 주소라 하면 머리속에 떠오는 것이 하나는 버스 주소일 겁니다. 
하지만 주소라는 것을 이런 제한적인 개념으로 보시지 말고 
어떤 디바이스를 접근하거나 다루기 위한 구별자로 보시는 것이 편합니다. 
CPU 의 주소 지정 역시 버스 주소가 아닌 구별자로써 의미를 갖습니다.
다음 CPU 노드에 대한 표현은 CPU 주소 지정에 대한 간단한 예입니다. 
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
};
cpu@1 {
compatible = "arm,cortex-a9";
reg = <1>;
};
};

각 CPU 의 선언에는 주소를 이용하여 하나의 고유 ID 를 주소로 부여하고,
크기에 대한 정보는 없음을 보여 주고 있습니다. 

위 예에서 cpus 노드에 "#address-cells" 은 1 로 설정하고 "#size-cells"은 0 으로 설정하고 있습니다. 

이 의미는  cpu 각각을 표현ㅎ는 자식 노드의 reg 속성 값의 셀들에 주소는 1개의 셀로 되어 있고 길이 값은 셀을 사용하지 않으므로 아예 없음을 나타냅니다.

좀 쉽게 이야기하면 reg 속성값에 셀들이 모두 주소란 이야기지요.. 

이전에 노드 이름을 지정할 때 주소는 구별하기 위한 값으로 어떤 것을 사용해도 된다고 말씀드렸습니다. 
하.. 지.. 만...
규정에는 노드의 reg 속성값으로 사용된 첫번째 주소 값을 노드 이름의 장치 주소에 사용하도록 하고 있습니다. 
위 예도 이름에 대하여 이런 룰을 적용하고 있습니다.
3.2 디바이스 메모리 주소 지정

이제 디바이스 에 주소 정보를 표현하는 방법을 알아 보겠습니다. 
CPU 를 다루는 것보다 조금 더 복잡하지만 속성의 사용법은 다른게 없습니다. 
우선 다음 예를 보아 주시기 바랍니다. 
/ {
#address-cells = <1>;
#size-cells = <1>;
...
serial@101f0000 {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
};
serial@101f2000 {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000 >;
};
gpio@101f3000 {
compatible = "arm,pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
};
interrupt-controller@10140000 {
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
};
spi@10115000 {
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
};
...
};
우선 디바이스 주소에 정보를 다루기 위해서 reg 속성을 사용합니다. 
그리고 reg 속성의 값에서 주소와 길이를 나타내기 위해서 사용하는 셀의 갯수를 나타내기 위해서 
먼저 각 디바이스 노드를 포함하는 부모 노드인 "/" 노드에서 
#address-cells 를 사용하여 시작 주소를 표현하기 위해 몇개의 셀을 사용하는지를 나타내고 있습니다.
여기서는 1 이므로 한개의 셀 즉 32 비트 부호없는 정수를 사용해서 시작 주소를 나타냄을 표현하고 있습니다.
마찬가지로 #size-cells 를 사용해서 길이를 나타내기 위해서 몇개의 셀을 사용하지도 나타내고 있습니다. 
일반적으로 이 셀 수는 32 비트 시스템에서는 1을 64 비트 시스템에서는 2를 사용합니다. 
위예에서  GPIO 디바이스 주소를 살표보면 
GPIO 디바이스 주소는 0x101f3000 ~ 0x101f3fff 와 0x101f4000 ~ 0x101f400f 의  두 개 주소 범위가 부여되고 있음을 알 수 있습니다. 
그런데 
노드들은 하부에 자식 노드들이 포함될 수 있고 해당 자식 노드 역시 reg 속성을 가질 수 있습니다. 
이때 #address-cells 과 #size-cells 은 특별히 아래에서 선언하지 않으면 상속되어 

계속 적용됩니다.
그런데 상위에서는 하나의 주소값만이 필요하지만 하부 노드에서는 두개의 셀로 구성된 주소값이 필요할 수도 있습니다. 
일단 예를 보겠습니다. 
external-bus {
#address-cells = <2>
#size-cells = <1>;
ethernet@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
};
i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
reg = <1 0 0x1000>;
rtc@58 {
compatible = "maxim,ds1338";
};
};
flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};

이 예를 보면 
#address-cells 속성에 2 를 부여하고 있음을 볼 수 있습니다. 
즉 주소를 표현하기 위해서 2개의 셀을 사용하고 있습니다. 
왜냐하면 i2c 에 대한 표현을 하기 위해서는 
버스 와 버스의 주소에 대한 두개의 정보가 필요하기 때문입니다. 
다른 말로 칩 선택 번호, 오프셋 이라고 하면 될 듯 합니다. 
이때 가장 상위의 노드 , 여기서는 external-bus 가 그 노드에 해당되는데, 
이 곳에서 #address-cells 과 #size-cells 로 그 하부의 노드들의 reg 속성 값에 대한 
사용 셀 수를 지정하고 있습니다. 
어떤 디바이스는 주소를 표현하는데 하나의 셀을 사용할 것이고 
어떤 디바이스는 두개의 셀을 사용할 것입니다. 
이런 경우에는 그 하부에 다시 셀에 대한 설정을 하지 않는다면 
가장 상위의 셀 수 에 대한 정의가 모두 적용되므로 
가장 많은 셀 수를 사용하는 디바이스 노드에 대한 수로 지정해 버리고 
하부의 모든 노드에 동일하게 표현하는 겁니다. 
여기서 기억해야 할 것이 
노드이름에 대한 장치 주소는 reg 속성의 첫번째 주소 지정의 값을 사용해야 한다고 했습니다. 
위 예에서 플래쉬의 경우를 보면 
노드 명을 "flash@2,0" 을 사용하고 있습니다. ',' 로 분리하고 있는데 
노드의 reg 속성에 첫번째 주소를 지정하기 위해서 2 와 0 을 사용하고 있습니다 .
이것을 ',' 로 분리해서 지정하고 있음을 기억해 주시기 바랍니다. 
3.3 직접 메모리 맵에 대상이 안되는 장치들 

어떤 디바이스들은 프로세서 버스에 직접 메모리 맵핑이 될 수 없는 것들이 있습니다. 
이런 예를 다음과 같이 들어 보겠습니다.

i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
rtc@58 {
compatible = "maxim,ds1338";
reg = <58>;
};
};
maxim 의 ds1338 디바이스는 i2c 버스 상에서 주소가 필요 합니다. 
이것은 CPU 의 로컬 버스 주소는 아니기 때문에 메모리 맵핑이 되지 않은 경우입니다. 
이런 경우에는 #address-cells 와 #size-cells 를 이용해서 하부에 대한 
셀 수를 재 지정합니다. 
이때는 길이에 대한 것이 없는 경우입니다. 

3.4 Ranges 속성(주소 번역)

지금까지 어떻게 디바이스에 주소를 부여하는지를 다루어 봤습니다. 
하지만 지금 까지 다룬 주소는 각 디바이스 노드의 입장에서 주소를 다룬 것입니다. 
i2c 버스에 연결된 디바이스를 제어하기 위해서는 i2c 버스 상에 표현되는 주소만 필요할 것입니다. 
CPU 에 연결된 시리얼 디바이스라면 CPU 와 연결된 로컬 버스상의 주소를 다룰 것입니다. 
하지만 i2c 버스에 연결된 디바이스를 CPU 입장에서 다룬다면 
CPU 는 로컬 버스 주소와 i2c 버스간에 변환 방법을 알아야 합니다. 
왜냐하면 CPU 입장에서는 i2c 버스의 주소 정보는 로컬 버스에 적용할 수 없기 때문입니다. 
디바이스 트리의 루트 노드는 보드 그 자체이고 루트 노드의 주소는 cpu 가 접근하는 주소 공간입니다. 

그래서 모든 주소 정보는 CPU  의 입장에서 해석 가능해야 합니다. 
조금 더 구체적으로 이야기 하면 
i2c 버스에 연결된 디바이스는 CPU의 주소 공간에서 직접적으로 접근이 불가능합니다.
반드시 i2c 컨트롤러를 이용하여 접근합니다. 
즉 i2c 버스에 연결된 디바이스는 i2c 버스에서 선택하고 접근할 수 있는 주소 뿐만아니라 
이런 정보를 적용할 i2c 컨트롤러와 연관된 주소도 알려 주어야 합니다. 
물론 모든 디바이스가 이런 제한을 갖는 것은 아닙니다. 

만약 serial 디바이스 가 CPU 의 도메인 공간에서 접근 할수 있는 로컬 버스에 연결되어 있고 맵핑되어 있다면
serial 디바이스 의 노드에 표현된 노드의 reg 속성에 있는 주소 정보는 CPU 입장에서는 바로 사용할 수 있습니다. 
그러나 앞에서 예를 든 i2c 버스에 연결된 디바이스는 
CPU 가 접근 가능한 i2c 컨트롤러와 관련된 부가 주소 정보를 더 제공해야 합니다.
정리하면 모든 디바이스들은 각 디바이스 노드의 주소 도메인과 
CPU 의 주소 도메인간의 변환이 가능하도록 관련된 정보를 제공해야합니다.
이런 정보를 제공하는 것이 바로 ranges 속성입니다. 
즉 부모 도메인과 자식 도메인간의 주소 변환 정보를 이 ranges 속성을 통해서 제공하는 것입니다. 
아래에 예는 ranges 속성을 어떻게 사용하는지에 대한 것 입니다. 

/ {
compatible = "acme,coyotes-revenge";
#address-cells = <1>;
#size-cells = <1>;
...
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
ethernet@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
};
i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
rtc@58 {
compatible = "maxim,ds1338";
reg = <58>;
};
};
flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
};
ranges 속성은 주소 변환에 관련된 정보를 제공하는 리스트 구조를 가집니다. 
ranges 속성의 값은 다음과 같은 형식을 갖습니다. 
ranges = <
자식주소1 부모주소1 자식주소크기1
자식주소2 부모주소2 자식주소크기2
자식주소3 부모주소3 자식주소크기3
자식주소4 부모주소4 자식주소크기4
 >; 

위 형식에서 보듯이 자식주소, 부모주소, 그 자식들의 주소 공간의 크기 의 묶음들의 리스트로 표현됩니다.
이 값을 지정하는 방식은 앞에서 설명했듯이 셀이라는 단위로 지정됩니다. 
그렇다면 각 주소와 크기를 나타내기 위해서 몇개의 셀이 사용되는지를 지정하는 속성이 예상됩니다. 
실제로 사용은 이미 앞에서 설명한 reg 에 사용된 것이 그대로 사용됩니다. 
자식 주소와 부모 주소의 셀 수를 지정하는 것은 이전에 사용했던 "#address-cells" 을 사용합니다. 
크기의 셀 수를 지정하는 것 역시 #size-cells 를 사용합니다. 
그런데 이 #address-cells 속성과 #size-cells 은 부모용과 자식용이 따로 없습니다. 
그렇기 때문에 부모 노드에서 지정한 #address-cells 속성 은 부모 주소의 셀수를 지정하고 
자식 노드에서 지정한 #address-cells 속성 은 자식 주소의 셀수를 지정합니다. 
자식 주소 크기를 나타내는 셀 수는 자식 노드에 선언된 #size-cells 속성에 지정된 크기를 셀 수로 사용합니다. 
이 설명을 아래예에 나타냈습니다. 
외쪽 화살표와 함께 사용한 주석을 잘 보시기 바랍니다. 
/ {
compatible = "acme,coyotes-revenge";
#address-cells = <1>;  <--- ranges 속성 값에서 부모 주소 셀 수 지정
#size-cells = <1>;
...
external-bus {
#address-cells = <2> <-- ranges 속성 값에서 자식 주소 셀 수 지정
#size-cells = <1>;  <-- ranges 속성 값에서 자식 주소 크기 셀 수 지정
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 속성에서 표시하는 자식 주소는 2개의 셀을 갖습니다. 
부모 주소는 1 개의 셀을 갖고 크기 역시 1개의 셀만을 사용하게 됩니다. 
그래서 위 예에서 ranges 속성에 첫번째 주소 변환 정보인
ranges = <0 0  0x10100000   0x10000
은 0 과 0 이 자식 주소 정보이고 0x10100000 은 부모 즉 CPU 입장에서 로컬 버스 주소가 되고 0x10000 은 자식 주소 크기가 됩니다. 
이것을 외부버스에 대한 해석을 한다면 다음과 같이 해석이 됩니다. 

칩 셀렉트 0 번의 오프셋 0은 0x10100000..0x1010ffff 의 주소 범위로 맵핑됩니다. 
칩 셀렉트 1 번의 오프셋 0은 0x10160000..0x1016ffff 의 주소 범위로 맵핑됩니다. 
칩 셀렉트 2 번의 오프셋 0은 0x30000000..0x10000000 의 주소 범위로 맵핑됩니다. 

(***) 아래 부분은 오역이 있을 수 있으므로 영어가 되시는 분은 꼭 원문을 확인해 보실것!!!
만약 부모와 자식 주소 공간이 동일하다면, 값이 빈 ranges 속성을 사용할 수 있습니다.
값이 빈 ranges 속성이 있다는 것은 자식의 주소 공간과 부모의 주소 공간이 1:1로  맵핑된다는 것을 의미합니다.
1:1 맵핑 되는 경우에도 ranges 속성을 사용해서 주소 변환 정보를 제공할 필요가 있을까 하는 궁금증이 생길수 있습니다 .
이런 경우의 예로 로컬 버스와 전혀 다른 주소 공간을 갖는 PCI 같은 특정 버스는 운영체제입장에서 로컬 메모리 공간으로 맵핑되어야 하고 보여야 합니다. 
또 다른 경우라면 어떤 디바이스는 DMA 엔진을 갖을 수 있는데 이와 관련된 처리를 하려면 실제 버스 상의 물리적 주소값을 알 필요가 있습니다. 
디바이스들이 동일한 소프트웨어적으로 프로그램 가능한 물리적 주소를 모두 공유하는 경우에 디바이스는 서로 구룹 지어질 필요도 있기 때문입니다. 
어떻든지 간에, 1:1 맵핑은 운영체제가 필요로 하거나 하드웨어 디자인에 따라서 필요하고 사용됩니다. 
여러분은 i2c@1,0  노드에 ranges 속성이 없음을 알려야 합니다. 
그 이유는 외부버스와 다르게, i2c 버스위에 있는 디바이스는 CPU 주소 영역에 메모리 주소 맵핑을 할 수 없기 때문입니다.
대신에, CPU는 rtc@58 디바이스는 i2c@1,0 를 통해서 간접적으로 접근합니다. 
ranges 속성이 없음은 해당 디바이스의 부모 이외엔 어떤 디바이스도 직접적인 접근을 할수 없음을 의미합니다.

(***) 여기까지 확인해 보실 것..
원문 
Alternately, if the parent and child address spaces are identical, then a node can instead add an empty ranges property. The presence of an empty ranges property means addresses in the child address space are mapped 1:1 onto the parent address space.
You might ask why address translation is used at all when it could all be written with 1:1 mapping. Some busses (like PCI) have entirely different address spaces whose details need to be exposed to the operating system. Others have DMA engines which need to know the real address on the bus. Sometimes devices need to be grouped together because they all share the same software programmable physical address mapping. Whether or not 1:1 mappings should be used depends a lot on the information needed by the Operating system, and on the hardware design.
You should also notice that there is no ranges property in the i2c@1,0 node. The reason for this is that unlike the external bus, devices on the i2c bus are not memory mapped on the CPU's address domain. Instead, the CPU indirectly accesses the rtc@58 device via the i2c@1,0 device. The lack of a ranges property means that a device cannot be directly accessed by any device other than it's parent.


신고

'Computer > Linux/Unix' 카테고리의 다른 글

디바이스 트리 작성법 (4편)  (0) 2015.03.24
디바이스 트리 작성법 (3편)  (0) 2015.03.24
디바이스 트리 작성법 (2편)  (1) 2015.03.24
디바이스 트리 작성법 (1편)  (0) 2015.03.24
[Linux] Module 관련  (0) 2015.03.13
[Makefile] Kbuild 와 Module Compile  (0) 2015.03.09


Posted by injunech