Embedded : : Linux/: : Device Tree

[Device Tree] 9. 커널 OF(Open Firmware) API

Jay.P Morgan 2026. 3. 4. 16:27

 

 

  9.  커널  OF(Open Firmware) API

 

  9.1  커널 OF_API란?

 

커널 OF_API (Open Firmware API) 리눅스 커널 드라이버가 메모리에 로드된 디바이스 트리(Live DT) 데이터에 접근하여 원하는 정보를 추출할 때 사용하는 함수 집합입니다.

디바이스 트리가 "데이터베이스"라면, OF_API는 그 데이터베이스에 쿼리를 날리는 "SQL"과 같은 역할을 합니다.

주로 include/linux/of.h에 정의되어 있습니다.

 

1. 주요 역할: 데이터 추출의 도구

드라이버는 부팅 시 전달받은 device_node 구조체 포인터를 가지고 다음과 같은 작업을 수행합니다.

  • 노드 찾기: 경로, 이름, 또는 compatible 문자열로 특정 노드를 검색합니다.
  • 프로퍼티 읽기: 정수(u32), 문자열, 불리언(boolean) 등 노드 내의 값을 가져옵니다.
  • 리소스 해석: 주소(reg), 인터럽트, 클럭, GPIO 등 복잡한 하드웨어 자원을 커널 객체로 변환합니다.

 

2. 자주 사용되는 주요 함수 (Cheat Sheet)

분  류 함 수 명 설    명
노드 검색 of_find_node_by_path() /soc/serial@1c28000 같은 전체 경로로 노드를 찾음
of_find_compatible_node() compatible 문자열이 일치하는 노드를 찾음
단일 값 읽기 of_property_read_u32() 32비트 정수 값을 읽음
of_property_read_string() 문자열 값을 읽음
of_property_read_bool() 해당 속성이 존재하는지 여부 확인 (True/False)
배열/리스트 of_property_read_u32_array() 여러 개의 정수 값(배열)을 한꺼번에 읽음
of_property_count_elems_of_size() 특정 속성에 몇 개의 데이터가 들어있는지 확인
리소스 연결 of_parse_phandle() 다른 노드를 가리키는 phandle을 따라가 해당 노드 포인터를 반환

 

 

3. 코드 예시: 드라이버에서의 실제 활용

드라이버의 probe 함수에서 OF_API를 사용하는 전형적인 패턴입니다.

#include <linux/of.h>

static int my_driver_probe(struct platform_device *pdev) {
    struct device_node *np = pdev->dev.of_node; // 현재 장치의 DT 노드
    u32 temp_limit;
    const char *mode;

    // 1. "temperature-limit" 이라는 u32 값 읽기
    if (of_property_read_u32(np, "temperature-limit", &temp_limit)) {
        temp_limit = 80; // 기본값 설정 (에러 시)
    }

    // 2. "operating-mode" 라는 문자열 읽기
    of_property_read_string(np, "operating-mode", &mode);

    // 3. "internal-pullup" 이라는 속성이 있는지 확인 (Boolean)
    if (of_property_read_bool(np, "internal-pullup")) {
        // 풀업 설정 로직 실행
    }

    return 0;
}

 

 

4. 핵심 구조체: struct device_node

OF_API가 대상으로 삼는 핵심 데이터 구조입니다. 커널 내부에서 디바이스 트리의 각 노드는 이 구조체로 관리됩니다.

주의사항: > of_find_... 계열 함수를 사용하여 노드를 직접 찾은 경우, 참조 카운트(Reference Count)가 증가합니다. 작업이 끝난 후에는 반드시 of_node_put(np)를 호출하여 메모리 누수를 방지해야 합니다. (단, pdev->dev.of_node 처럼 자동으로 전달받은 노드는 직접 해제할 필요가 없습니다.)

 

 

정리하자면...

OF_API는 하드웨어 배치도(DTS)에 적힌 텍스트 정보를 드라이버가 이해할 수 있는 C언어 변수와 객체로 바꾸어주는 통역사입니다.

 

 

  9.2  커널 OF API 참조가이드 코드

 

리눅스 커널 드라이버 개발을 위한 "OF(Open Firmware) API 치트 시트(Cheat Sheet)" 또는 참조용 가이드 코드로 보입니다.

정확히는 include/linux/of.h와 그 하위 헤더 파일들에 정의된 함수들을 실무에서 어떻게 사용하는지 핵심만 모아놓은 요약본입니다.

 

 

 
  #include <linux/of.h>
  #include <linux/of_device.h>
  #include <linux/of_address.h>
  #include <linux/of_irq.h>
  #include <linux/of_gpio.h>
 
  /* ===== 프로퍼티 읽기 ===== */
 
  u32 val;
  of_property_read_u32(np, "my-prop", &val);              /* u32 1개 */
 
  u32 arr[4];
  of_property_read_u32_array(np, "my-array", arr, 4);    /* u32 배열 */
 
  u64 val64;
  of_property_read_u64(np, "my-u64", &val64);          /* u64 */
 
  const char *str;
  of_property_read_string(np, "label", &str);                  /* 문자열 */
 
  int count = of_property_read_string_helper(               /* 문자열 목록 */
       np, "clock-names", NULL, 0, 0);
 
  bool present = of_property_read_bool(np, "big-endian");     /* boolean */
 
  /* ===== 노드 탐색 ===== */
 
  struct device_node *child;
  for_each_child_of_node(np, child) {                               /* 자식 순회 */
  /* child 처리... */
  }
 
  struct device_node *node;
  node = of_find_compatible_node(NULL, NULL,
          "myvendor,my-device");                                           /* compatible로 검색 */
 
  node = of_find_node_by_path("/soc/serial@1c28000");     /* 경로로 검색 */
 
  node = of_parse_phandle(np, "clocks", 0);                    /* phandle 참조 해석 */
 
  /* ===== 리소스 가져오기 ===== */
 
  struct resource res;
  of_address_to_resource(np, 0, &res);                             /* reg → struct resource */
  void __iomem *base = of_iomap(np, 0);                          /* reg → ioremap */
 
  int irq = of_irq_get(np, 0);                                                  /* interrupts → IRQ 번호 */
  int irq2 = platform_get_irq(pdev, 0);                                 /* platform 래퍼 (권장) */
 
  /* ===== compatible 매칭 확인 ===== */
 
  bool match = of_device_is_compatible(np, "vendor,dev");
 
  const struct of_device_id *id;
  id = of_match_device(my_of_ids, &pdev->dev);
  if  (id && id->data) {
         /* match-specific 데이터 사용 */
         const struct my_hw_data *hw = id->data;
  }
 

 


이 코드가 보여주는 핵심 맥락 3가지

1. 프로퍼티 추출 (Property Extraction)

DTS에 적힌 텍스트 데이터를 C언어 변수로 옮기는 과정입니다.

  • of_property_read_u32, of_property_read_string 등은 드라이버의 probe 함수에서 가장 먼저 실행되는 코드들입니다.
  • 하드웨어의 설정값(예: 전압 제한, 모드 설정 등)을 가져올 때 사용됩니다.

2. 노드 탐색 및 참조 (Node Navigation)

트리 구조 내에서 원하는 장치를 찾거나 연결된 장치를 추적하는 과정입니다.

  • for_each_child_of_node: I2C 컨트롤러 드라이버가 자기 밑에 달린 센서들을 하나씩 확인할 때 사용합니다.
  • of_parse_phandle: "이 장치가 쓰는 클럭은 저쪽 클럭 컨트롤러에 있어"라는 연결 고리를 따라갈 때 사용합니다.

3. 리소스 변환 (Resource Mapping)

가장 중요한 부분으로, DTS의 추상적인 숫자를 커널이 제어할 수 있는 실제 메모리 주소와 인터럽트 번호로 바꾸는 과정입니다.

  • of_iomap: DTS의 reg 주소를 커널 가상 주소로 매핑하여 직접 레지스터를 읽고 쓸 수 있게 해줍니다.
  • of_irq_get: 하드웨어 핀 번호를 커널 시스템의 IRQ 번호로 변환합니다.

위 코드의 성격: 보통 다음과 같은 곳에서 자주 발견됩니다.

  1. 커널 공식 문서의 예제: Documentation/devicetree/ 경로에 있는 설명 문서들.
  2. 드라이버 개발 튜토리얼: 임베디드 리눅스 교육 자료나 블로그의 "Hello World" 드라이버 예제.
  3. 커널 내부 테스트 코드: drivers/of/unittest.c와 같이 API 동작을 검증하기 위한 코드.

💡 팁: 실제 드라이버 작성 시 주의점

위 코드 중 of_find_... of_parse_phandle처럼 노드를 직접 찾는 함수들은 사용 후 반드시 of_node_put(node)를 호출해야 합니다. 커널은 내부적으로 노드의 참조 횟수(Reference Count)를 관리하기 때문에, 이를 잊으면 메모리 누수가 발생할 수 있습니다.

반면, pdev->dev.of_node를 통해 전달받은 노드는 플랫폼 버스가 관리해주므로 직접 해제할 필요가 없습니다.

 

 

 

참고: https://www.minzkn.com/linuxkernel/pages/device-tree.html#dt-device-node