[U-BOOT] 드라이버 ID정보와 dts활용
U-BOOT device driver
작성일 기준 최신 u-boot의 구조는 커널의 구조와 유사합니다.
여러가지 칩을 커버하기 위해서는 드라이버의 발전도
여러 칩을 커버하기 위한 방향으로 발전해야 합니다.
하나의 인터페이스를 다양한 환경(soc)에서 적용할 수 있는
최소한의 드라이버를 개발하기 위해서는
soc를 구분할 수 있는 기법이 중요 합니다.
비단, u-boot 드라이버 만의 얘기가 아닙니다.
드라이버 입장에서는 현재 사용중인 soc 자체는 무의미하고,
특정 정보를 파싱해서 적절한 함수를 call 하면 그만입니다.
parse device-tree
리눅스 커널은 늘어가는 디바이스를 효율적으로 관리하기 위해
device-tree를 도입했습니다.
U-BOOT도 역시 커널을 따라 갑니다.
디바이스 트리의 property를 parsing한 정보대로만 명령을 실행합니다.
아래 몇가지 예제가 있습니다.
(커널에도 역시 비슷한 역할을 하는 API가 존재합니다.)
U-BOOT에서는 dts parsing API dev_read_TYPE 이 있습니다.
...
#address-cells = <1>;
#size-cells = <1>;
...
foo@71004000 {
compatible = "steve,foo";
regs = <0x71004000 0x4>;
clock = <&clk_peri PERI_TCT>;
clock-frequency = "1000000";
};
uint32_t reg;
uint32_t freq;
reg = dev_read_addr_index(dev, 0);
freq = dev_read_u32(dev, "clock-frequency");
이와 같은 경우, reg에는 0x71004000 freq에는 1000000이 저장됩니다.
parse udevice id
device를 구분하려면 매핑 테이블이 필요합니다.
U-BOOT에서는 udevice_id 타입을 많이 사용합니다.
매핑 테이블에서는 주로 compatible과 data로 device를 구분할 수 있습니다.
struct udevice_id {
const char *compatible;
ulong data;
};
static const struct udevice_id bar_ids[] = {
{ .compatible = "steve,foo", .data = FOO_DATA },
{ }
};
U_BOOT_DRIVER(bar) = {
.name = "bar",
.id = UCLASS_BAR,
.of_match = bar_ids,
.ops = &bar_ops,
.probe = bar_probe,
.of_to_plat = bar_ofdata_to_platdata,
};
compatible 속성으로 드라이버를 구분하고,
data 속성으로 동일한 드라이버 내에서 동작을 구분할 수 있습니다.
data 속성을 활용하기 위해서 of_to_plat 과 연결된
함수 내에서 dev_get_driver_data(dev) 을 활용할 수 있습니다.
struct foo_dev {
int data;
};
static int bar_ofdata_to_platdata(udevice dev)
{
struct foo_dev *foo = dev_get_priv(dev);
...
foo->data = dev_get_driver_data(dev);
}
dev_get_priv 은 udevice 의 private 정보를 넘기는 API 입니다.
- driver_data를 get 하는 시점은 드라이버 probe 여도 무방합니다.
Leave a comment