1. 程式人生 > >第18章 ARM Linux裝置樹之四(常用的OF API)

第18章 ARM Linux裝置樹之四(常用的OF API)

18.4 常用的OF API

除了前文介紹的of_machine_is_compatible()、of_device_is_compatible()等常用函式以外,在Linux的BSP和驅動程式碼中,經常會使用到一些Linux中其他裝置樹的API,這些API通常被冠以of_字首,實現程式碼位於核心的drivers/of目錄下。

這些常用的API包括下面內容。

1.尋找節點

struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible);

根據相容屬性,獲得裝置節點。遍歷裝置樹中的裝置節點,看看哪個節點的型別、相容屬性與本函式的輸入引數匹配,在大多數情況下,from、type為NULL,則表示遍歷所有節點。

2.讀取屬性

int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz);
int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz);
int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz);

int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value);

讀取裝置節點np的屬性名,為propname,屬性型別為8、16、32、64位整型陣列。對於32位處理器來講,最常用的是of_property_read_u32_array()。

如在arch/arm/mm/cache-l2x0.c中,通過如下語句可讀取L2cache的"arm,data-latency"屬性:

of_property_read_u32_array(np, "arm,data-latency", data, ARRAY_SIZE(data));

在arch/arm/boot/dts/vexpress-v2p-ca9.dts中,對應的含有"arm,data-latency"屬性的L2cache節點如下:

L2: [email protected] {
        compatible = "arm,pl310-cache";
        reg = <0x1e00a000 0x1000>;
        interrupts = <0 43 4>;
        cache-level = <2>;
        arm,data-latency = <1 1 1>;
        arm,tag-latency = <1 1 1>;

};

在有些情況下,整型屬性的長度可能為1,於是核心為了方便呼叫者,又在上述API的基礎上封裝出更加簡單的讀單一整形屬性的API,它們為int of_property_read_u8()、of_property_read_u16()等,實現於include/linux/of.h中,如程式碼清單18.19所示。

程式碼清單18.19 裝置樹中整型屬性的讀取API

static inline int of_property_read_u8(const struct device_node *np, 
                                       const char *propname,
                                       u8 *out_value)
{
        return of_property_read_u8_array(np, propname, out_value, 1);
}


static inline int of_property_read_u16(const struct device_node *np, 
                                       const char *propname,
                                       u16 *out_value)
{
        return of_property_read_u16_array(np, propname, out_value, 1);
}


static inline int of_property_read_u32(const struct device_node *np, 
                                       const char *propname,
                                       u32 *out_value)
{
        return of_property_read_u32_array(np, propname, out_value, 1);
}

除了整型屬性外,字串屬性也比較常用,其對應的API包括:

int of_property_read_string(struct device_node *np, const char *propname,const char **out_string);
int of_property_read_string_index(struct device_node *np, const char *propname,int index, const char **output);

前者讀取字串屬性,後者讀取字串陣列屬性中的第index個字串。

除整型、字串以外的最常用屬性型別就是布林型,其對應的API很簡單,具體如下

static inline bool of_property_read_bool(const struct device_node *np, const char *propname);
如果裝置節點np含有propname屬性,則返回true,否則返回false。一般用於檢查空屬性是否存在。

3.記憶體對映

void __iomem *of_iomap(struct device_node *node, int index);

上述API可以直接通過裝置節點進行裝置記憶體區間的ioremap(),index是記憶體段的索引。若裝置節點的reg屬性有多段,可通過index標示要ioremap()的是哪一段,在只有1段的情況,index為0。採用裝置樹後,一些裝置驅動通過of_iomap()而不再通過傳統的ioremap()進行對映,傳統的ioremap()的使用者也不少。

int of_address_to_resource(struct device_node *dev, int index, struct resource *r);

上述API通過裝置節點獲取與它對應的記憶體資源的resource結構體。其本質是分析reg屬性以獲取記憶體基地址、大小等資訊並填充到struct resource*r引數指向的結構體中。

4.解析中斷

unsigned int irq_of_parse_and_map(struct device_node *dev, int index);

通過裝置樹獲得裝置的中斷號,是從.dts中的interrupts屬性裡解析出中斷號。若裝置使用了多箇中斷,index指定中斷的索引號。

5.獲取與節點對應的platform_device

struct platform_device *of_find_device_by_node(struct device_node *np);

在可以拿到device_node的情況下,如果想反向獲取對應的platform_device,可使用上述API。

在已知platform_device的情況下,想獲取device_node則易如反掌,例如:

static int sirfsoc_dma_probe(struct platform_device *op)
{
        struct device_node *dn = op->dev.of_node;
        …
}

18.5 總結

ARM Linux開始圍繞裝置樹展開,裝置樹有自己的獨立語法,它的原始檔為.dts,編譯後得到.dtb,Bootloader在引導Linux核心的時候會將.dtb地址告知核心。之後核心會展開裝置樹並建立和註冊相關的裝置,因此arch/arm/mach-xxx和arch/arm/plat-xxx中的大量用於註冊platform、I2C、SPI等板級資訊的程式碼被刪除,而驅動以新的方式與在.dts中定義的裝置節點進行匹配。