天天看點

RK3399 探索之旅 / 裝置樹速讀 / Soc 基礎設施1. 簡介2. 檢視 Soc 框圖3. 确定 dts 檔案關系4. 彙總完整的 dts 節點5. 檢視 Soc 基礎設施6. 相關參考思考技術,也思考人生

哈喽,老吳又來分享學習心得啦。目前,我已經從 hardware enable 工程師更新為 dts 工程師了。

1. 簡介

思考一下,bringup 一款 Soc 的最小操作包括哪些?

  • 添加 Soc 層次的 Device Tree (arch/arm64/boot/dts/);
  • 添加 Timer driver (drviers/clksource/);
  • 添加 Interrupt controller driver (drivers/irqchip);
  • 添加 Serial port driver (drivers/tty/serial);

完成上面 4 個步驟後,就有機會啟動系統進入指令行終端了。

接下來需要完善什麼?

  • 添加 Pin muxing control driver (drivers/pintrl);
  • 添加 Clocks driver (drivers/clk/);
  • 添加 GPIO driver (drivers/gpio/);
  • 添加 SMP 的支援;
  • 添加 Network driver;
  • 添加各種 controller driver;
  • 添加各種 device driver;

本文會順着上述思路,快速地浏覽一下 NanoPC-T4 這塊單闆的裝置樹裡 Soc 基礎設施。

2. 檢視 Soc 框圖

RK3399 探索之旅 / 裝置樹速讀 / Soc 基礎設施1. 簡介2. 檢視 Soc 框圖3. 确定 dts 檔案關系4. 彙總完整的 dts 節點5. 檢視 Soc 基礎設施6. 相關參考思考技術,也思考人生

點選檢視大圖

rk3399 大緻包括 7 個部分:

  • ARM Processor
  • System Peripheral
  • Multi-Media Processor
  • Connectivity
  • Multi-Media Interface
  • External Memory Interface
  • Embedded Memory

閱讀裝置樹時,Soc 框圖可以協助我們确定好每個節點的定位和功能。

3. 确定 dts 檔案關系

dts 檔案關系圖:

RK3399 探索之旅 / 裝置樹速讀 / Soc 基礎設施1. 簡介2. 檢視 Soc 框圖3. 确定 dts 檔案關系4. 彙總完整的 dts 節點5. 檢視 Soc 基礎設施6. 相關參考思考技術,也思考人生

點選檢視大圖

rk3399-nanopi4-rev00.dts 和 rk3399-nanopi4-common.dtsi 用于描述闆級資訊;

rk3399.dtsi 等剩下的檔案用于描述 Soc 資訊;

4. 彙總完整的 dts 節點

完整的 dts 節點圖:

RK3399 探索之旅 / 裝置樹速讀 / Soc 基礎設施1. 簡介2. 檢視 Soc 框圖3. 确定 dts 檔案關系4. 彙總完整的 dts 節點5. 檢視 Soc 基礎設施6. 相關參考思考技術,也思考人生

點選檢視大圖

5. 檢視 Soc 基礎設施

5.1 cpus 節點

cpus {
    #address-cells = <2>;
    #size-cells = <0>;

    cpu-map {
        cluster0 {
            core0 {
                cpu = <&cpu_l0>;
            };
            ...
            core3 {
                cpu = <&cpu_l3>;
            };
        };

        cluster1 {
            core0 {
                cpu = <&cpu_b0>;
            };
            core1 {
                cpu = <&cpu_b1>;
            };
        };
    };
    cpu_l0: [email protected] {
        device_type = "cpu";
        compatible = "arm,cortex-a53", "arm,armv8";
        ...
    };
    ...
    cpu_b0: [email protected] {
        device_type = "cpu";
        compatible = "arm,cortex-a72", "arm,armv8";
    };
    ...
}
           

簡單說明:

  • rk3399 有 4 個 a53 小核和 2 個 a72 大核。在 ARM 架構中,cpus 節點用于描述 cpu 核心的布局,cpus 節點下的每一個 cpu 節點代表一個 cpu 核心,上述裝置樹描述了。
  • cpu-map 節點用于描述 ARM cpu 的拓撲結構,SMP 處理器才需要這個節點。
  • cpu-map 可包含 3 種類型的實體:cluster(叢集) / core / thread,cluster 裡可以包含 1 個或多個 cluster/core。

相關代碼:

  • 暫不關心,待定;

相關文檔:

  • Documentation/devicetree/bindings/arm/cpus.txt
  • Documentation/devicetree/bindings/arm/topology.txt

相關接口:

  • /sys/devices/system/cpu,所有 cpu 相關的資訊和支援的操作都在這個目錄下。

5.2 clock controller 節點

/arch/arm64/boot/dts/rockchip/rk3399.dtsi

cru: [email protected] {
    compatible = "rockchip,rk3399-cru";
    reg = <0x0 0xff760000 0x0 0x1000>;
    #clock-cells = <1>;
    #reset-cells = <1>;
    assigned-clocks = ...;
    assigned-clock-rates = ...;
};
           
/arch/arm64/boot/dts/rockchip/rk3399.dtsi

pmucru: [email protected] {
    compatible = "rockchip,rk3399-pmucru";
    reg = <0x0 0xff750000 0x0 0x1000>;
    #clock-cells = <1>;
    #reset-cells = <1>;
    assigned-clocks = ...;
    assigned-clock-rates = ...;
};
           

簡單說明:

  • rk3399 的 clock controller 包括 cru 和 pmucru 2部分,cru 是 clock & reset unit 的縮寫,pmu 是 power management unit 的縮寫。
  • clock controller 負責生成時鐘并将其提供給 SoC 中的各種控制器,并且還為 SoC 外設實作了reset controller。
  • cru 和 pmucru 都是 clock provider, #clock-cells 表明clock consumer 需要用多少個單元才能引用 cru/pmucru 提供的 clock。
  • 通過 assigned-clocks 和 assigned-clock-rates 指定了一些 clock 的初始頻率,包括 PLL、總線、VOP、GPU等。

相關文檔:

  • Documentation/devicetree/bindings/clock/arm-integrator.txt
  • Documentation/devicetree/bindings/clock/rockchip,rk3399-cru.txt

相關代碼:

  • drivers/clk/rockchip/clk-rk3399.c

相關接口:

  • /sys/kernel/debug/clk/clk_summary,用于檢視時鐘樹

5.3 interrupt controller 節點

gic: [email protected] {
    compatible = "arm,gic-v3";
    ...
    its: [email protected] {
        compatible = "arm,gic-v3-its";
        #interrupt-cells = <4>;
        ...
        interrupt-controller;
        ...
    };

    ppi-partitions {
        ppi_cluster0: interrupt-partition-0 {
            affinity = <&cpu_l0 &cpu_l1 &cpu_l2 &cpu_l3>;
        };

        ppi_cluster1: interrupt-partition-1 {
            affinity = <&cpu_b0 &cpu_b1>;
        };
    };
};
           

簡單說明:

  • rk3399 使用中斷控制器是 gic-v3。
  • gic-v3 是 ARM Generic Interrupt Controller, version 3 的縮寫,是一款 ARM 出品的通用中斷控制器。
  • AArch64 SMP 核心通常與 GICv3 搭配使用,GICv3 提供了專用外設中斷(PPI),共享外設中斷(SPI),軟體生成的中斷(SGI)和特定于區域的外設中斷(LPI)。
  • interrupt-controller 屬性用于标志一個中斷控制器節點,#interrupt-cells = <4> 表明 Interrupt client devices 需要用 4 個單元才能确定引用的中斷,例如 interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW 0>。

相關代碼:

  • drivers/irqchip/irq-gic-v3.c

相關文檔:

  • Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
  • Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
  • Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt

相關接口:

  • /sys/kernel/irq

5.4 pin controller 節點

pinctrl: pinctrl {
    compatible = "rockchip,rk3399-pinctrl";
    ...

    // 4 x gpio controller
    gpio0: [email protected] {
        compatible = "rockchip,gpio-bank";
        ...
    };
    ...

    // lots of pin configuration nodes
    ...
    i2c0 {
        i2c0_xfer: i2c0-xfer {
            rockchip,pins =
                <1 15 RK_FUNC_2 &pcfg_pull_none>,
                <1 16 RK_FUNC_2 &pcfg_pull_none>;
        };
    };
    ...
}
           

簡單說明:

  • rk3399 的 pin controller 包括 2 個部分:4 個 gpio controller 節點 + 一堆的引腳配置子節點。
  • pin controller 負責提供配置引腳複用,驅動強度,上下拉的功能。
  • Soc 裡的其他 controllers 或者 device drivers 通過引用 pin controller 裡的引腳配置子節點來配置引腳,它們被稱為 pinctrl client devices。
  • 引腳配置子節點有 2 種類型:pin multiplexing(引腳複用) 和 pin configuration(引腳驅動強度、上下拉)。
  • rk3399 的 4.4 核心裡 pinctrl 的 pin multiplexing 節點格式是 rockhip原廠 自己定義的: rockchip,pins,在更高版本的核心裡應該會被修改為更通用的方式:pins。

相關代碼:

  • drivers/pinctrl/pinctrl-rockchip.c

相關文檔:

  • Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
  • Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt

相關接口:

$ tree /sys/kernel/debug/pinctrl
/sys/kernel/debug/pinctrl
├── pinctrl-devices
├── pinctrl-handles
├── pinctrl-maps
└── pinctrl-rockchip-pinctrl
    ├── gpio-ranges
    ├── pinconf-config
    ├── pinconf-groups
    ├── pinconf-pins
    ├── pingroups
    ├── pinmux-functions
    ├── pinmux-pins
    └── pins
           

5.5 gpio controller 節點

gpio0: [email protected] {
    compatible = "rockchip,gpio-bank";
    reg = <0x0 0xff720000 0x0 0x100>;
    clocks = <&pmucru PCLK_GPIO0_PMU>;
    interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH 0>;

    gpio-controller;
    #gpio-cells = <0x2>;

    interrupt-controller;
    #interrupt-cells = <0x2>;
};
...
gpio4: [email protected] {
    compatible = "rockchip,gpio-bank";
    ...
};
           

簡單說明:

  • rk3399 共有 5 個 gpio controller,122 個 gpio,所有的 gpio 都可以産生中斷,上電後預設都是 input 狀态。
  • gpio-controller 屬性表明這個一是 gpio 控制器節點,#gpio-cells = <2> 表明 gpio client devices 需要用 2 個單元才能确定引用的引腳。
  • interrupt-controller 屬性表明 rk3399 的 gpio controller 也有中斷控制器的功能,#interrupt-cells = <0x2> 表明需要 2 個單元來确定引用的中斷,例如:interrupt-parent = <&gpio1>; interrupts = <20 IRQ_TYPE_EDGE_FALLING>。
  • 在rk3399 裝置樹裡引用 gpio 的方式是:gpio = <&gpio0 1 GPIO_ACTIVE_HIGH>,如果需要引用多個 gpio,則使用 gpios 屬性。

相關代碼:

  • drivers/pinctrl/pinctrl-rockchip.c,和 pin controller 的驅動是同一個,說明 pinctrl 和 gpio 關聯是很緊密的。

相關文檔:

  • Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
  • Documentation//devicetree/bindings/gpio/gpio.txt

相關接口:

  • /sys/class/gpio,傳統的接口。
  • /dev/gpiochip0,比較推薦的接口。
  • libgpiod,推薦使用該庫。

5.6 efuse 節點

efuse0: [email protected] {
    compatible = "rockchip,rk3399-efuse";
    ...
    /* Data cells */
    specification_serial_number: [email protected] {
        reg = <0x06 0x1>;
        bits = <0 5>;
    };
    cpu_id: [email protected] {
        reg = <0x07 0x10>;
    };
    ...
};
           

簡單說明:

  • efuse 是一次性可程式設計存儲器。
  • Data cells 子節點提供了rk3399 efuse 内部的資料布局;

相關代碼:

  • driver/nvmem/rockchip-efuse.c

相關文檔:

  • Documentation/devicetree/bindings/nvmem/nvmem.txt

相關接口:

  • sys/devices/platform/ff690000.efuse/rockchip-efuse0/nvmem

5.7 cpuinfo 節點

cpuinfo {
    compatible = "rockchip,cpuinfo";
    nvmem-cells = <&cpu_id>;
    nvmem-cell-names = "id";
};
           

簡單說明:

  • rockchip 自家的東西,用于提供 cpu id;
  • NVMEM 是 Non Volatile Memory 的縮寫,用于驅動晶片内的 efuse / eeprom。在 efuse 中一般會儲存着例如 cpu id 之類的晶片相關的硬體資訊,參考前面的 efuse. 節點;
  • cpuinfo 是 NVMEM 的 data consumer;
  • nvmem-cells 引用的是 cpu_id 資料,啟動時會列印 cpu id,對應的 log 是: rockchip-cpuinfo cpuinfo: xxx;

相關代碼:

  • driver/soc/rockchip/rockchip-cpuinfo.c

相關文檔:

  • Documentation/devicetree/bindings/soc/rockchip/rockchip-cpuinfo.txt

6. 相關參考

  • Rockchip_RK3399TRM_V1.4_Part1-20170408.pdf
  • Rockchip RK3399 Datasheet V2.1-20200323.pdf
  • GICv3_v4_overview.pdf

思考技術,也思考人生

要學習技術,更要學習如何生活。

你和我各有一個蘋果,如果我們交換蘋果的話,我們還是隻有一個蘋果。但當你和我各有一個想法,我們交換想法的話,我們就都有兩個想法了。

對 嵌入式系統 (Linux、RTOS、OpenWrt、Android) 和 開源軟體 感興趣,關注公衆号:嵌入式Hacker。

覺得文章對你有價值,不妨點個 在看和贊。