你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32MP157系列教程连载-Linux系统移植篇3:STM32MP微处理器之设备树简介

[复制链接]
STMCU小助手 发布时间:2022-9-20 22:01
第 1 章 设备树详解
9 _; o1 @5 I& o# p6 p1 E4 q
' J+ P9 W) m3 P7 b% v# {$ I6 y1.1 简介. G5 S; h5 P0 M# a+ f/ r

( f7 g, s& `6 \$ w3 A7 z2 ~在传统Linux内核中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,比如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data,这些板级细节代码对内核来讲只不过是垃圾代码。而采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码,导致ARM的merge工作量较大。后经过一些讨论,对ARM平台的相关code做出如下相关规范调整,这个也正是引入DTS的原因。
' W1 d) F. H: T$ s5 d
' n! c% L, m. d1、ARM的核心代码仍然保存在arch/arm目录下
$ `# Z  d4 a9 E  B) }1 u9 T2、ARM SoC core architecture code保存在arch/arm目录下
" X" n3 k( u" q) U4 Z3、ARM SOC的周边外设模块的驱动保存在drivers目录下
; ~8 z% |/ T2 @) Q4、ARM SOC的特定代码在arch/arm/mach-xxx目录下6 {& V$ l. i8 ^& Y
5、ARM SOC board specific的代码被移除,由DeviceTree机制来负责传递硬件拓扑和硬件资源信息。, B- ~! r/ M; y3 k9 A8 G
5 k& @6 B1 Y8 t( A8 u
本质上,Device Tree改变了原来用code方式将硬件配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。对于嵌入式系统,在系统启动阶段,bootloader会加载内核并将控制权转交给内核,此外,还需要把上述的三个参数信息传递给kernel,以便kernel可以有较大的灵活性。在linux kernel中,Device Tree的设计目标就是如此。
* L5 U) m" A( j) d+ E; G6 q2 G1 {& [* j' z$ ?
在devie tree中,可描述的信息包括:& t0 D! V% C( C

, n5 c3 M  n, e  C* G6 A1、CPU的数量和类别
9 U7 O8 h2 X, K$ d' F8 x2、内存基地址和大小5 n1 h6 o! N! a! F4 ^; R
3、总线和桥. m1 |+ s) u1 h/ P- e' V# T3 j
4、外设连接
4 i( W; H/ ?( W; E5、中断控制器和中断的使用情况
+ c. H/ U" P3 [3 _( p9 d* w6、GPIO控制器和GPIO使用情况
9 r; }" O$ d% @9 n3 _7、clock控制器和clock使用情况
4 f( t; R; g+ i" ^/ C# e
5 Z4 p4 ^) B% w2 [* L0 e- c它基本就是一棵电路板上的CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核来识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给内核,内核会将这些资源绑定给展开的相应设备。
' C  C# R+ y9 z4 k8 J3 E0 z2 c# ~+ \2 S+ E* u
Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离。在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写。引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码。比如在ARM Linux内,一个.dts(device tree source)文件对应一个ARM的machine,一般放置在内核的"arch/arm/boot/dts/“目录内,比如stmp1a-dk1参考板的板级设备树文件就是"arch/arm/boot/dts/ stm32mp157a-dk1.dts”。这个文件可以通过make dtbs命令编译成二进制的.dtb文件供内核驱动使用。
- c/ i) C+ K6 R% q& [8 U' a* R6 R. {) _2 O
基于同样的软件分层设计的思想,由于一个SoC可能对应多个machine,如果每个machine的设备树都写成一个完全独立的.dts文件,那么势必相当一些.dts文件有重复的部分,为了解决这个问题,Linux设备树目录把一个SoC公用的部分或者多个machine共同的部分提炼为相应的.dtsi文件。这样每个.dts就只有自己差异的部分,公有的部分只需要"include"相应的.dtsi文件, 这样就是整个设备树的管理更加有序。我这里用Linux4.19.94源码自带的goodix touchscreen触摸芯片为例来分析设备树的使用和移植。这个触摸芯片的设备树节点信息在" Documentation/devicetree/bindings/input/touchscreen/goodix.txt"有详细说明,其驱动源码是" drivers/input/touchscreen/goodix.c"。
# N4 r/ q" O9 F8 L
0 |, O! |- _6 u& Y! Q1.2 基础知识介绍
- ~  Y: h6 f' |. X
" r2 _. V/ M! P8 ?8 U: i# adts
+ A2 b, R, e% \0 I硬件的相应信息都会写在.dts为后缀的文件中,每一款硬件可以单独写一份例如stm32mp157a-dk1.dts,一般在Linux源码中存在大量的dts文件,对于arm架构可以在arch/arm/boot/dts找到相应的dts,一个dts文件对应一个ARM的machie。
6 Q" k6 x! K6 @. W4 a
7 E% f8 I2 v7 ]dtsi
0 ?4 w$ B* |; J) M. {' T值得一提的是,对于一些相同的dts配置可以抽象到dtsi文件中,然后类似于C语言的方式可以include到dts文件中,对于同一个节点的设置情况,dts中的配置会覆盖dtsi中的配置。) q4 X9 N+ @" U7 Y9 u/ Q3 T
$ z1 W9 ?: B$ v* P# x
dtc
* p, ]* ~$ t3 q' \: Q- g" k  Ydtc是编译dts的工具,可以在Ubuntu系统上通过指令apt-get install device-tree-compiler安装dtc工具,不过在内核源码scripts/dtc路径下已经包含了dtc工具;! h. F) x0 o! J) a

; g5 y8 w) b; y1 s5 ndtb
; N% c/ p- f' B  ldtb(Device Tree Blob),dts经过dtc编译之后会得到dtb文件,dtb通过Bootloader引导程序加载到内核。所以Bootloader需要支持设备树才行;Kernel也需要加入设备树的支持;1 W9 Q3 S  a: R' ]
2 _6 Q! Q7 L+ h' [2 K
1.3 DTS结构8 F6 }7 T6 d% D6 g- ], a

$ d8 O. Q: u1 Q
  1. /dts-v1/;
    , _5 b+ k3 I, \) _
  2. / {
    + E3 v- i1 P) _' ]) _8 d7 P  N4 V
  3.     node1 {
    ' g6 c- j7 m, ~; z! y# p
  4.         a-string-property = "A string";: w0 [9 f' n9 H! c/ `4 Y! j
  5.         a-string-list-property = "first string", "second string";6 w6 x8 L5 D0 R
  6.         // hex is implied in byte arrays. no '0x' prefix is required
    " X/ \0 {% q+ S4 u- i7 W; j, L
  7.         a-byte-data-property = [01 23 34 56];( ^" |1 b  ?3 q9 m2 R: a% C
  8.         child-node1 {
    : R. H; {, X5 \# y3 G4 [
  9.             first-child-property;
    # d/ e. q( R$ ^6 S
  10.             second-child-property = <1>;: u* `5 D/ W! J: R) T  z* @
  11.             a-string-property = "Hello, world";! T! V4 u" f- U2 F5 z, G& A
  12.         };' N2 t8 z3 Y) Y7 ?0 M; J
  13.         child-node2 {
    , _% O, ~1 k9 l/ ]4 _" Z0 c
  14.         };2 k9 _  Q, I8 p: [
  15.     };: }2 @; t1 k1 ^; C! V" {' ]- r
  16.     node2 {
    ) j% {( y  V0 c
  17.         an-empty-property;, ?/ l2 M. r0 `  W$ s& N3 x' G3 Q
  18.         a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */- c2 I: o, `) f& B0 b) [, b
  19.         child-node1 {
    - n/ Y9 A$ j# f: X8 e
  20.         };* D: J, u5 H8 F. O- ]
  21.     };% c; y1 b% N9 l9 q
  22. };
复制代码

4 n/ c' Y! Q8 p% a7 Q( D& ~/ Ddevice tree的基本单元是node。这些node被组织成树状结构,除了root node,每个node都只有一个parent。一个device tree文件中只能有一个root node。每个node中包含了若干的property/value来描述该node的一些特性。每个node用节点名字(node name)标识,节点名字的格式是node-name@unit-address。如果该node没有reg属性(后面会描述这个property),那么该节点名字中必须不能包括@和unit-address。unit-address的具体格式是和设备挂在那个bus上相关。例如对于cpu,其unit-address就是从0开始编址,以此加一。而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。root node的node name是确定的,必须是“/”。; e: E  ~( t: T! ]3 p
  L- o; F1 T! k
也就是说设备树源文件的结构为:. d( `( S+ p( `7 e9 Q
1.1个root节点”/”;
5 y- w0 R3 z& X8 r+ N8 @% m2.root节点下面含一系列子节点,“node1” and “node2”) a, O$ r) g2 J' @1 {6 ]( m$ g& e
3.节点node1和下又含有一系列子节点,“child-node1” and “child-node2”5 @1 n0 l( C+ L
4.各个节点都有一系列属性
0 r3 ~# t) Z; z8 t: q这些属性可能为空,如an-empty-property
7 _- d3 L$ g, c& M可能为字符串,如a-string-property
; i, W& D6 V4 m+ R- K可能为字符串树组,如a-string-list-property9 ^* M+ B/ L+ I' I! z! a
可能为Cells(由u32整数组成),如second-child-property
* H  m9 b" H' K' w9 R1.4 DTS语法介绍/ V' f7 ~5 q: d. A/ U. Z- V* K

$ l' j% c0 \5 K" o  d; u了解了基本的device tree的结构后,我们总要把这些结构体现在device tree source code上来。在linux kernel中,扩展名是dts的文件就是描述硬件信息的device tree source file,在dts文件中,一个node被定义成如下格式:+ }8 }6 l+ F) n3 y

1 v/ x. ~: n( t7 x9 |
  1. [label:] node-name[@unit-address] {
    5 j: o/ J  A, L7 U2 {+ v
  2.    [properties definitions]; }0 p4 e: T& z% ~% O
  3.    [child nodes]
    7 Q4 r! ?" V  Z6 p+ R% l% y
  4. }
复制代码

  W$ F1 H# |2 }) n, E) N  ~1 o“[]”表示option,因此可以定义一个只有node name的空节点,label方便在dts文件中引用。# H* i' q2 W/ l( B) q+ `$ X7 X
% I  E* f& _: V% U5 `! w
基本数据类型:  b/ [* Q- I" n* x

8 v# s) p, P4 e- c( n7 T3 xtext string(以null结束),以双引号括起来,如:string-property = “a string”;* T' D4 N8 b6 Q2 Q1 o! k7 k
cells 是32位无符号整形数,以尖括号括起来,如:cell-property = <0xbeef 123 0xabcd1234>;
% I. \8 w' ?1 y$ x! U$ Z. b: gbinary data 以方括号括起来,如:binary-property = [0x01 0x23 0x45 0x67];
$ V& M1 S  K- l% V. n7 N不同类型数据可以在同一个属性中存在,以逗号分格,如:mixed-property = “a string”, [0x01 0x23 0x45 0x67],<0x12345678>;" G) i# H4 `2 H$ T1 w6 }
多个字符串组成的列表也使用逗号分格,如:string-list = “red fish”,”blue fish”;2 p) S) o3 z# c1 ]1 u
  c+ i5 b- g8 Q2 a) J
1.5 dts的组成
$ [+ j+ a1 P' i5 w* i" z' A/ e# u& V' ^& ~8 H! {' ^8 M
1.5.1 compatible1 J2 H& D8 V2 J9 X- M; }

2 {/ }& r& S  M2 v/ ]/ M9 J! O每一个dts文件都是由一个root的根节点组成,内核通过根节点“/”的兼容性即可判断它启动的是什么设备,其代码结构如下
2 P( d+ d5 y2 t' U8 R
3 g8 ]. Y4 s; ~4 k9 J
  1. / {# f- Z% G" e  o
  2.     model = "HQYJ FS-MP1A Discovery Board";
    2 |3 G/ A) ?, p. K3 `+ E1 k1 D
  3.     compatible = "st,stm32mp157a-dk1", "st,stm32mp157", "hqyj,fsmp1a";
    9 R1 T0 L1 Q) W6 F  x  \$ F0 Q% X
  4. 0 F1 a# I' M( v' x" V+ [9 n
  5.     aliases {2 L6 z, O5 q; @) f5 E
  6.         ethernet0 = ðernet0;6 j, w" `! d. Z% }
  7.         serial0 = &uart4;
    , b% r/ [! G, c/ F' ?+ \
  8.         serial5 = &usart3;9 u% a2 ?* G* a9 Y; m
  9.     };! a9 P8 \' @+ q& ?7 I4 O

  10. ; R1 Z; @. Y7 O
  11.     chosen {
    2 N' v- x' }& J3 B, l, `( c
  12.         stdout-path = "serial0:115200n8";" V1 s& w; n% \- ~* _7 o
  13.     };
    7 @0 U9 `3 h2 w; J% ~9 j
  14.     ... ...
    7 V7 a8 B- g5 l
  15. };
复制代码
5 `6 j% y  S' J6 O* ]6 [
model属性值是,它指定制造商的设备型号。推荐的格式是:“manufacturer,model”,其中manufacturer是一个字符串描述制造商的名称,而型号指定型号。
) @. }% a' G8 I8 {+ Z# ~1 C$ `4 c; r2 M# m% E5 g
compatible属性值是,指定了系统的名称,是一个字符串列表,它包含了一个“<制造商>,<型号>”形式的字符串。重要的是要指定一个确切的设备,并且包括制造商的名字,以避免命名空间冲突。+ {1 X2 f5 U' L% K2 V5 G

% J6 J. T- q6 Rchosen 节点不代表一个真正的设备,但功能与在固件和操作系统间传递数据的地点一样,如根参数,取代以前bootloader的启动参数,控制台的输入输出参数等。7 w  j1 W0 e& h9 G' A
' R4 S2 G& a) g$ q) `6 V" `' _  w
1.5.2 #address-cells和#size-cells
% T4 K) U- P+ S/ I: K# S0 `
8 V8 W3 e9 d. r' R# G
  1. port {! n2 B$ G  p) j' |: ~
  2.     #address-cells = <1>;: ^4 X$ U" M6 P; x7 D
  3.     #size-cells = <0>;
    / ?3 x" V" w7 s3 A# a& d
  4. / Y2 o) a$ S3 {
  5.     ltdc_ep0_out: endpoint@0 {
    0 l8 [$ D& g+ G' M( q  A" l
  6.         reg = <0>;) H+ n/ D2 T5 V! Q/ E1 L% S$ O
  7.         remote-endpoint = <&sii9022_in>;- e' |/ G9 |2 j2 X; Z2 O7 c
  8.     };
    / G: `" N/ ]8 K, w0 Q
  9. };
复制代码

# H$ ?1 f' n8 k#address-cells = <1>: 基地址、片选号等绝对起始地址所占字长,单位uint32。. f5 B; @! L# q: v2 h
#size-cells = <1>: 长度所占字长,单位uint32。
1 f% e9 q5 H" o' o$ R7 I
6 c$ r" a- X( ]) X1.5.3 CPU addressing' p5 ^* J) |9 u5 g

$ Z' R+ l& @* g  E" A! Z5 G# ]* C在讨论寻址时,CPU节点代表了最简单的情况。 每个CPU都分配有一个唯一的ID,并且没有与CPU ID相关联的大小。
8 \: j- q- }2 Q  y) K7 x; W" S* k- }" W3 w  x6 `3 v
  1. cpus {7 K2 v& a* I& {: D
  2.     #address-cells = <1>;
    / b6 U9 W6 W$ T8 x% f  B5 I% u1 d! Y
  3.     #size-cells = <0>;1 T2 [% z/ C4 S6 m) P4 K% p

  4. + @1 ?( l- w6 g) Q
  5.     cpu0: cpu@0 {
    ; a1 ?4 k" Z4 T+ k6 P1 `7 ]' I5 e1 s
  6.         compatible = "arm,cortex-a7";& o1 e; G$ U, q% [7 H/ ]2 S
  7.         device_type = "cpu";
    5 m2 a6 Z1 s. G' y+ l" d/ K9 ]4 S
  8.         reg = <0>;7 t- v; u# e& n; ~- l
  9.         clocks = <&rcc CK_MPU>;
    + s& j8 u* L9 g# i% f3 ^1 m6 K
  10.         clock-names = "cpu";+ C2 k2 A7 i6 b& r8 h/ N
  11.         operating-points-v2 = <&cpu0_opp_table>;, l( D' p. F) R5 i' L4 f
  12.         nvmem-cells = <&part_number_otp>;; z# f* Y* Z7 y- \& L4 _6 v
  13.         nvmem-cell-names = "part_number";  P! `  o# v9 h# H
  14.     };7 V  Z% x: H1 k- M

  15. # o* `- i. l- |  Z5 L1 v9 A( e
  16.     cpu1: cpu@1 {9 ^4 ^8 ]. Y. a& }6 u; E9 U" ?# d
  17.         compatible = "arm,cortex-a7";: z3 V7 c. M' [3 |! |. T5 `
  18.         device_type = "cpu";( X+ t$ t0 u; C' |' n& L: R: @. \& {
  19.         reg = <1>;
    1 G( x$ J$ c+ C7 e
  20.         clocks = <&rcc CK_MPU>;
    2 K# i/ q. F5 ]
  21.         clock-names = "cpu";  f8 v0 X6 d  |! J" g0 x
  22.         operating-points-v2 = <&cpu0_opp_table>;
    5 S5 {9 i- h- y$ u
  23.     };: j2 H1 b, _6 z" C
  24. };
复制代码
2 ]1 e  Q3 d: |- |9 L6 ]$ a
在cpus节点,#address-cells被设置成了1,#size-cells被设置成了0。这是说子reg值是单独的uint32,它用无大小字段表示地址。在此情况下,这两个cpu分配到的地址为0和1。cpu节点的#size-cells是0因为每个cpu只分配到了一个单独的地址。( e0 p3 r9 F1 _: e
4 y( N! x1 O7 t/ E9 T/ ~0 f
你仍然需要注意reg值班需要与节点名的值相匹配。按照惯例,如果一个节点有一个reg属性,那么这个节点名称必须包括unit-address,这是reg属性的第一个address值。" c" S! L- |$ c6 c4 n- p: k
; q& j- J, R5 n: c  K3 B4 _1 d0 {$ {
1.5.4 Memory Mapped Devices: Q& j# v0 ?; \+ I) ~) @' C
$ x7 u+ s7 @+ m! g
与在cpu节点中单独的address值不同,内存映射设备被分配了一系列将要响应的地址,因此不仅需要包含内存的基地址而且还需要映射地址的长度,因此需要使用#size-cells用来表示在每个子reg元组中长度字段的大小。在以下示例中,每个address值为1 cell(32 bits),每个长度值也是1 cell,这在32 bit系统是比较典型的。64 bit设备也许会为#address-cells和#size-cells使用数值2,在device tree中获取64 bit addressing。
( e, Q% G. _5 U- ^( F; y0 P  ?5 F2 @4 s+ q: d5 _
  1. /dts-v1/;
    6 m3 K" O; b, y. N
  2. / {
    - |, u* m" f6 P8 {' [/ k
  3.     #address-cells = <1>;- z  H, _0 s* `" {3 `$ b
  4.     #size-cells = <1>;
    9 V  u, Q0 G; P7 v* c4 n
  5.     ...
    , U2 P3 e8 s5 h! N8 o0 N
  6.     timers2: timer@40000000 {
    2 J1 e0 T0 @* S9 |6 h3 I7 y9 F8 f
  7.         compatible = "st,stm32-timers";5 Q" y0 B# M$ l6 o5 H% t* V) J' ]: G
  8.         reg = <0x40000000 0x400>;; R0 \) @6 a2 z3 B7 s5 D
  9.     };- ?! f! O+ `" s& d3 q+ d, K4 M

  10. ) z3 k8 b0 i! R& o4 F$ Z
  11.     timers3: timer@40001000 {- A7 v, t5 N' r
  12.         compatible = "st,stm32-timers";  W$ J, Q* @( v
  13.         reg = <0x40001000 0x400>;4 T3 \5 [( ~5 ]" j
  14.     };& @, d* V7 s' h
  15. 8 d/ @" `! }2 t9 g& d
  16.     spi2: spi@4000b000 {2 r' f+ l7 u" }" G
  17.         compatible = "st,stm32h7-spi";& }3 k( f' M, C( f
  18.         reg = <0x4000b000 0x400>;
    4 _/ C- a* P& A" r0 M
  19.     };  @4 |) E2 b' t- y

  20. 8 D. z% h# L2 p' r9 U
  21.     uart7: serial@40018000 {
    - G$ U# O3 G. }- T. \
  22.         compatible = "st,stm32h7-uart";! R4 T. n: ~7 I: G3 K4 h
  23.         reg = <0x40018000 0x400>;$ o& K5 @0 |! K+ C4 j6 }
  24.     };# z- d( ~6 \9 B4 e6 Y+ f/ l

  25. - Z( F8 W  T. t: R8 V$ B
  26.     sai1: sai@4400a000 {
    " l! u" {4 {" W3 ?6 d
  27.         compatible = "st,stm32h7-sai";
    7 |; Z: I7 t2 u
  28.         reg = <0x4400a000 0x4>;
    " p6 X* R" [' j: o. k8 r0 g
  29.     };- Z* U- B6 O# e& o% \
  30.     ...3 D& Z0 ], p( [3 k7 S3 b! ^
  31. };
复制代码
1.55 Non Memory Mapped Devices( u7 Z/ Y" B) ]6 r' m

9 e; g- Q2 o3 `5 [9 M" f! U处理器总线的其它设备为非内存映射设备。他们有地址范围,但不能被CPU直接寻址。母设备的驱动程序将代替CPU进行间接访问。以i2c设备为例,每个设备都分配了一个地址,但没有长度或范围与之相匹配。这与CPU地址分配很相似。! }2 Q  p$ d7 o( i9 y" y' J

2 o7 \& w! j1 o! l
  1. etf: etf@50092000 {
    , O% a4 m$ n& G. c
  2.     compatible = "arm,coresight-tmc", "arm,primecell";
    & H1 ^+ ?' y) V! U& C. @; Y+ U
  3.     reg = <0x50092000 0x1000>;
    ; ]0 i, i* b9 f
  4.     clocks = <&rcc CK_TRACE>;9 F/ T- k) m' z" C  y: v
  5.     clock-names = "apb_pclk";
    : _. D( l$ Q3 Z8 e8 N2 ~
  6. 2 U# _' b9 |: e& S
  7.     ports {  `2 ~+ F3 K# \& n8 O8 U+ e4 H2 F7 O8 E
  8.         #address-cells = <1>;
    * d2 k! y$ [2 o' `
  9.         #size-cells = <0>;
      P* t6 r: z) [

  10. . L/ z  v2 F8 _, R
  11.         port@0 {
    # I+ q2 \+ e  W4 s- E% d7 ~
  12.             reg = <0>;
    5 Y, z, A( ]% H* T2 ?
  13.             etf_in_port: endpoint {1 V2 K8 b) W& Z
  14.                 slave-mode;
    + s) V& `) i8 r6 a
  15.                 remote-endpoint = <&funnel_out_port0>;
    * n5 v! l3 ]) |$ f
  16.             };8 k0 t* T* p" {) t6 ^% O; Y* b
  17.         };
    % t. o$ u, ]4 y) J9 a) i+ o% w% O+ G
  18. 7 M2 n% {/ h) s" ~
  19.         port@1 {7 C" t- m2 d: [& X
  20.             reg = <0>;
    0 [7 {. Z- z. {7 A  f; Z- h
  21.             etf_out_port: endpoint {/ Y+ t/ |# ]2 g$ ~
  22.                 remote-endpoint = <&tpiu_in_port>;, I& o, T+ S2 q! Y
  23.             };7 S! G9 r9 A6 M
  24.         };, E/ s7 M. n! B* p5 i
  25.     };0 m# N' `  {" K9 q
  26. };
复制代码
- z5 ^. @" P: a& ]: V: ?
+ E4 c: |% ~( e! a5 z1 Y  l
1.5.6 Ranges (Address Translation)4 e2 X' j' i2 _% \% V) w) f, u2 V( ~

4 P4 `  X7 C3 ]; m# W# T5 K* h前面已经讨论过如何向设备分配地址,但此时这些地址只是本地设备节点,还没有说明如何从那些地址里映射到cpu可以使用的地址。根节点经常描述地址空间的CPU视图。根节点的子节点已经使用了CPU的address domain,所以不需要任何明确的映射。例如,serial@101f0000设备被直接分配了地址0x101f0000。3 X5 m6 E% E, {' v* S
1 {6 k  @" U* w9 h, G$ U- W' R
根节点的非直接子节点是无法使用CPU的address domain的。为了在deivce tree获取内存映射地址必须指定如何从一个域名将地址转换到另一个。Ranges属性就用于此目的。以下是添加了ranges属性的device tree示例。
! K9 z8 l! \2 Q- J  q9 c
1 k3 N6 j/ R( q9 I; z. Q7 e
  1. m4_rproc: m4@0 {
    4 q9 `5 V7 v: L! B
  2.     compatible = "st,stm32mp1-rproc";
    0 P7 ~, _( H: `. a; @3 c, ^
  3.     #address-cells = <1>;* @! N3 h. L# R6 I
  4.     #size-cells = <1>;
    6 s* y: f* W- ^& ^

  5. ( L. g5 p# S8 G, n8 r4 k* F
  6.     ranges = <0x00000000 0x38000000 0x10000>,
    % h) B) l/ M6 F. @: x
  7.          <0x30000000 0x30000000 0x60000>,( L5 d7 Z9 e5 c: Y- \3 e! }" A
  8.          <0x10000000 0x10000000 0x60000>;; f/ r' v8 V& ?: e, ]5 e- F- m3 ]
  9.     resets = <&rcc MCU_R>;5 `0 e/ j% n$ _0 J, P
  10.     reset-names = "mcu_rst";$ p6 {; C; Y& M
  11.     st,syscfg-pdds = <&pwr 0x014 0x1>;" g! Z' y6 g6 x, P. B. G0 z& N0 X
  12.     st,syscfg-holdboot = <&rcc 0x10C 0x1>;
    9 C  u7 h% x! J# F$ _: s# [6 H3 z
  13.     st,syscfg-tz = <&rcc 0x000 0x1>;
    ! y8 \' A& a* w4 [
  14.     st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>;
      W$ `0 K# M' P% Y- V
  15.     status = "disabled";
    - @& N/ n9 s8 k/ e. r( k* ~

  16. % H$ \# \, {/ @& x% b: z1 s
  17.     m4_system_resources {: b. w5 F2 @. n) C' p
  18.         compatible = "rproc-srm-core";
    0 s8 W  y  j- z# m, x& U- b. Q
  19.         status = "disabled";3 N0 _) F6 t* j8 o$ s
  20.     };1 C/ |; r3 Q; X/ B$ K. d
  21. };
复制代码
( I# R' V) M  q3 ~
ranges是一个地址转换列表。每个输入ranges表格的是包含子地址的元组,母地址和子地址空间的范围大小。每个字段的大小都由获取的子地址的#address-cells值,母地址的#address-cell值和子地址的#size-cells值而定。以外部总线为例,子地址是2 cells,母地址是1 cell,大小也为1 cell。
. ?+ y5 F  w1 r, }+ I. q$ L1 t& d1 Z( {3 f
1.5.7 status* L+ ?" {, Y- r/ n3 ^6 ?3 t
device tree中的status标识了设备的状态,使用status可以去禁止设备或者启用设备,看下设备树规范中的status可选值。
# b6 ^, M) r4 j, o2 i6 l
) u+ o. p2 \; e* | 20201123162532327.png # U  L( t+ `- M% O4 _" ^' i# ^

3 y/ C) M) U- o% s& ?1.5.8 中断映射
% @1 s. W  q1 `. M1 `与遵循树的自然结构而进行的地址转换不同,机器上的任何设备都可以发起和终止中断信号。另外地址的编址也不同于中断信号,前者是设备树的自然表示,而后者者表现为独立于设备树结构的节点之间的链接。: U0 h  y; F$ V

0 ^* Q5 T( b! V- |! u 20201123162010629.png
& Y% T0 w! q( `, I3 E4 G6 ?: l; ?. P" _' ?6 u$ `
下面显示了ADC控制器中断设备片段5 f  v: i" N4 z& L

$ `% E  k5 q$ m. C6 `+ H; Q% z9 b
  1. adc: adc@48003000 {, S, a7 G  _, p
  2.     compatible = "st,stm32mp1-adc-core";1 J3 d. Z3 ^1 G3 V# J4 J4 O
  3.     reg = <0x48003000 0x400>;9 l: \, f! K; [8 p( V. P& O
  4.     interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,1 B8 B% h( I. b8 X% Z3 I& C
  5.              <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
    ) F$ h1 E7 G4 B$ c
  6.     clocks = <&rcc ADC12>, <&rcc ADC12_K>;
    $ x, m2 p- r3 D4 i
  7.     clock-names = "bus", "adc";0 U0 T# N6 c) z; r) ?, c; a& P
  8.     interrupt-controller;
    3 V. F2 I, {3 M2 ]+ H$ I  j8 b
  9.     st,syscfg-vbooster = <&syscfg 0x4 0x100>;' o: k$ F- k, N
  10.     st,syscfg-vbooster-clr = <&syscfg 0x44 0x100>;
    + X% q$ e. _2 {- I
  11.     st,syscfg-anaswvdd = <&syscfg 0x4 0x200>;  ]7 I/ a' c& T' C. M& Y
  12.     st,syscfg-anaswvdd-clr = <&syscfg 0x44 0x200>;7 Z( Y$ |, g& ^+ @% u( ?0 D
  13.     #interrupt-cells = <1>;6 M. e- V. \4 ?& M. F+ C. y
  14.     #address-cells = <1>;
    # K  R8 q  N+ j) d! x
  15.     #size-cells = <0>;
    - Z* Y6 ~, c9 J. j" V7 w" `
  16.     status = "disabled";) u- F2 O4 c& Q3 r# k9 c
  17.   h0 L$ q, Q1 J2 s7 Y- V, [
  18.     adc1: adc@0 {
    # W" f$ \1 h- R: u
  19.         compatible = "st,stm32mp1-adc";
    8 j, _. u6 x. E! t7 g- }1 p
  20.         #io-channel-cells = <1>;; J: P4 e' l5 _1 D/ E" s" j7 l4 h7 u
  21.         reg = <0x0>;
    ( K' z, m6 c) B2 n. d' f. |
  22.         interrupt-parent = <&adc>;
    ' t4 e0 v6 c+ X: @/ T
  23.         interrupts = <0>;
    ) k; Z6 I( Q. o5 a) X9 N
  24.         dmas = <&dmamux1 9 0x400 0x05>;
    - @, \6 Z* c3 l. i8 s  S
  25.         dma-names = "rx";
    ! _1 B; \2 V8 e( k8 {( v9 G
  26.         status = "disabled";
    ) S7 h7 z4 t. ]$ n# L7 O4 h
  27.     };) l, k' B5 T7 _4 y. X; v3 {6 J
  28. & i4 h4 ^3 a) w# X: F) X
  29.     adc2: adc@100 {3 }+ [9 q: ?1 D( i& M
  30.         compatible = "st,stm32mp1-adc";
    . N. b" ~  y( a. j7 d
  31.         #io-channel-cells = <1>;
    4 H8 ?% n' u8 a
  32.         reg = <0x100>;
    % w$ s8 k) l: ^
  33.         interrupt-parent = <&adc>;
    " V, g  E- N% A3 x
  34.         interrupts = <1>;
    # ?% I" A' N- Z/ x" c8 ^
  35.         dmas = <&dmamux1 10 0x400 0x05>;# ]( a: T, V, G0 ?2 n. E
  36.         dma-names = "rx";
    + L$ Y- P+ S- F9 M! N4 R
  37.         /* temperature sensor */) }) P- I: a+ w  j
  38.         st,adc-channels = <12>;" B+ S+ R: j7 v  z- k# D" C
  39.         st,min-sample-time-nsecs = <10000>;
    + J. X+ h' I* n/ v' A# w
  40.         status = "disabled";6 _* c! F3 {- ~2 z! s: @
  41.     };
    2 H, G1 i1 V# o, o* s0 N# P
  42. * C( Y! g" Y( d% z1 @
  43.     jadc1: jadc@0 {
    * x% o' \1 @+ \
  44.         compatible = "st,stm32mp1-adc";% @' M+ V8 F- k( _  m: N6 Y
  45.         st,injected;9 h7 O% G. }) X% t
  46.         #io-channel-cells = <1>;
    & G; a/ |1 F0 _- N9 p! C9 R. T
  47.         reg = <0x0>;2 i, h, @& T4 N4 I5 k+ ?/ J
  48.         interrupt-parent = <&adc>;
    & C3 p8 x. R  }' g  M
  49.         interrupts = <3>;
    5 e# j  L$ Z: ]/ @  t
  50.         status = "disabled";1 u6 R3 ~' a/ ~: @+ m: z! C
  51.     };
    8 J1 _% R' T8 m* S  S) q  U
  52. - Y% ~, p' e! ^
  53.     jadc2: jadc@100 {
    $ A) n$ g/ e) K& m# a, v5 p
  54.         compatible = "st,stm32mp1-adc";" S" d9 W2 ~7 M8 ?; y  g/ y" o$ X
  55.         st,injected;( C0 ^" I# ?  u2 w) {( e
  56.         #io-channel-cells = <1>;
    $ P& u% p: k) y4 V" }8 ?4 R
  57.         reg = <0x100>;$ {; e3 q' q/ U: U- i- b" C% z
  58.         interrupt-parent = <&adc>;8 N3 |6 l% J6 V" M: n6 _. N
  59.         interrupts = <4>;
    # R/ r, f& n0 v$ `
  60.         /* temperature sensor */
    4 ?5 Q4 @8 B3 |* T* Z
  61.         st,adc-channels = <12>;
    * V" v8 J) p" m; `4 P3 a3 L! c( }
  62.         st,min-sample-time-nsecs = <10000>;7 B$ d7 @# Q2 I; l
  63.         status = "disabled";
    6 p0 f; e6 B1 ]
  64.     };3 Z6 {: g0 l8 H+ `0 Z

  65. : C% `) ]4 [& u
  66.     adc_temp: temp {. v+ G3 z, Y" P5 ~8 g- p+ M
  67.         compatible = "st,stm32mp1-adc-temp";
    6 b8 C& @2 J4 ^5 M+ L
  68.         io-channels = <&adc2 12>;
    " v  B- s9 s5 Z
  69.         nvmem-cells = <&ts_cal1>, <&ts_cal2>;
    ' N% @1 f9 @0 n; R; X2 K: [
  70.         nvmem-cell-names = "ts_cal1", "ts_cal2";& h+ B* i0 x4 y  K: s! R
  71.         #io-channel-cells = <0>;
    # x, K$ |* ^2 m' q1 v
  72.         #thermal-sensor-cells = <0>;
    4 T5 m! c) J) k1 D3 j! m8 V/ f. A) l
  73.         status = "disabled";3 a, K/ E: o. k% |- [) H) u* l
  74.     };2 i# w5 H9 G$ X! V: e# z0 u- m! u
  75. };
复制代码

  a+ v0 z6 O% L2 S下面显示了ethernet控制器中断设备片段" C; p$ t3 I) Q; `

  ~: N' w- T2 N6 I" C% s2 x" b
  1. ethernet0: ethernet@5800a000 {/ a9 j5 P" J# i5 I
  2.     compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";
    6 ?* E3 b0 Z% l0 v7 u
  3.     reg = <0x5800a000 0x2000>;
    0 i/ N& z( g/ x
  4.     reg-names = "stmmaceth";
    % J% w1 G3 Z% a! S) N$ w
  5.     interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>,1 p3 V) @9 H" _" ^% |
  6.                   <&intc GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>,
    . i$ G# Q0 y9 l7 u( X$ l
  7.                   <&exti 70 1>;0 A: h; B  q0 }/ g) C* N+ b, w; R
  8.     interrupt-names = "macirq",
    & j  j+ S. B0 P9 O# b  ?
  9.               "eth_wake_irq",
    5 v) O6 y* d6 [3 Q% A
  10.               "stm32_pwr_wakeup";, z7 A) b1 r+ n' W
  11.     clock-names = "stmmaceth",
    2 ?% e2 B! ^  M' K1 {4 d$ F. X% G
  12.               "mac-clk-tx",
    ' ?' |- P" \" ?3 c
  13.               "mac-clk-rx",
    ! _  ^% d( a  K1 T* Y
  14.               "ethstp";
    % ?0 @! }$ t" ~! O6 R: k
  15.     clocks = <&rcc ETHMAC>,1 ?: J. A( l& w  d
  16.          <&rcc ETHTX>,
    ; k& _( N+ G) Q1 d; C1 m  G4 X4 M
  17.          <&rcc ETHRX>,
    4 a2 d, J  a8 h+ l; V% d
  18.          <&rcc ETHSTP>;' z/ ^3 @1 P8 e* `  Z# M
  19.     st,syscon = <&syscfg 0x4>;
      D- S( K0 c; z3 j
  20.     snps,mixed-burst;
    6 ^. T% [9 e' c; u1 a
  21.     snps,pbl = <2>;5 A- X' I1 |: ~
  22.     snps,en-tx-lpi-clockgating;: S5 ~2 `# Y7 o8 n, w1 d- X% h. y. a
  23.     snps,axi-config = <&stmmac_axi_config_0>;
    + t) M! g4 t* d' r8 \
  24.     snps,tso;
    ) z& v# d3 t5 W$ ~% Z$ V" w
  25.     power-domains = <&pd_core>;- ~  x; p. }" g# V* ?% \
  26.     status = "disabled";, r2 n' ]2 I6 O
  27. };: k% Z* B* ], M2 B) }
复制代码
: Q, K! I. _/ K' l+ A
20201123162540968.png
' b' N( x+ W: i  e7 z, A2 J3 N; N) A6 O/ g: y8 D1 H1 {
1.5.9 特殊节点1 r! G, E& b* F5 X8 f' F
& ]. a; g! J5 X
aliases节点为了解决节点路径名过长的问题,引入了节点别名的概念,可以引用到一个全路径的节点。如/external-bus/ethernet@0,0,但当用户想知道具体内容的时候显得太累赘。) T$ l2 W0 r  C: r3 m0 u) @0 j! D
+ v9 ^" [9 ?3 m) _  _
  1. aliases {# ^1 [: b* G: z1 L) t2 C$ x& w
  2.     ethernet0 = ðernet0;4 {2 a) t9 P: v$ k2 i8 L1 d( _
  3.     serial0 = &uart4;9 F# O7 `4 p7 F
  4.     serial5 = &usart3;* j, z8 _7 `. K- x* l6 h: X
  5. };
复制代码

- a( |$ `) _: x当为设备分配一个标识符的时候,操作系统更倾向于使用aliases。
% J+ z, l1 R9 s, }0 j( d————————————————8 S) H; g- S% g; U7 {- V0 H' S& O
版权声明:左月先生
8 }7 O0 k4 c1 w5 l5 H3 |+ Y: o! V) _5 i1 ], L
' _5 z7 t$ M$ ?% s/ E  y9 Z4 N
赞 收藏 评论0 发布时间:2022-9-20 22:01

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版