summaryrefslogtreecommitdiff
path: root/kernel-devel/dts/pres_devicetree_en.tex
blob: 6b6ba5a05f3fb70c94031c64cf6753127344ccd3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
\input{configpres}

\title{Device Tree}
\maketitle

\subsection{Device Tree}

\begin{frame}
\frametitle{Overview}
\tableofcontents
\end{frame}

\subsubsection{Background, Scope, Advantages}
\begin{frame}
\frametitle{Open Firmware (OF)}
\begin{itemize}
\item Designed by Sun in the late 1980's
\item Popular on PowerPCs
\item Similar to BIOS or EFI
\item Integrated shell
\item Supports FCode: platform/architecture independent bytecode
\begin{itemize}
\item Boot-time diagnostics
\item Configuration code
\item Device drivers
\end{itemize}
\item Defines a standard way to describe the hardware of a system (Device Tree)
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Device Tree (DT)}
\begin{itemize}
\item HW initialization was hardcoded in C before.
\pause
\item Derived from the device tree format used by OF.
\pause
\item DT spec \url{https://www.devicetree.org/specifications/}
\pause
\item DT spec is implemented by Linux, FreeBSD, zephyr, u-boot, Android.
\pause
\item Human readable source files: .dts and .dtsi
\pause
\item DT compile (dtc) transfers between source and binary (.dtb).
\pause
\item The binary format is called Flattened Device Tree (FDT).
\pause
\item FDT is passed to the kernel, kernel transfers it into an Expandable Device Tree (EDT).
\pause
\item EDT snippets are passed to 'matching' probe functions.
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{DT and Linux}
\begin{description}
\item[1995] sparc/prom/tree.c written by David S. Miller
\pause
\item[2002] ppc64/kernel/prom.c Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner (IBM)
\pause
\item[2005] powerpc/kernel/prom.c copied from ppc64 to powerpc
\pause
\item[2007] Stephen Rothwell started to merge code from different architectures into drivers/of/base.c
\pause
\item[2009] 98 dts files in v2.6.30 (arm64, microblaze, powerpc)
\pause
\item[2011] Grant Likely added OF/DTS support for ARM (32-bit)
\pause
\item[2012] 165 dts files in v3.2 (+x86, +openrisc, +arm)
\pause
\item[2014] 648 dts files in v3.16 (+metag +c6x +arc +xtensa +mips)
\pause
\item[2016] 1199 dts files in v4.9 (+nios2 +h8300 +cris +sh)
\pause
\item[2018] 1612 dts files in v4.20 (-cris -metag +nds32)
\pause
\item[2019] there are still some board files (e.g. arch/arm/mach-omap1/board-nokia770.c)
\end{description}
\pause
DTS as a part of OF became the quasi standard for describing non-iteratable
hardware layouts to the Linux kernel.
\end{frame}

\begin{frame}
\frametitle{DT Scope}
Split HW specific information from Kernel binary
\begin{itemize}
\item The number and type of CPUs
\item Base addresses and size of RAM
\item Busses and bridges
\item Peripheral device connections
\item Interrupt controllers and IRQ line connections
\item Pin multiplexing
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Advantages}
\begin{itemize}
\item Single kernel can support multiple SoCs
\item Smaller amount of board support code
\item Xilinx FPGA tools do DTS generation
\item U-Boot can inspect and modify FDT before booting
\end{itemize}
\end{frame}

\subsubsection{Syntax}
\begin{frame}[fragile]
\frametitle{The .dts Syntax}
\includegraphics[width=8cm]{images/device-tree-syntax.jpg}
\\ \tiny Source: http://wiki.dreamrunner.org
\normalsize \\ \url{https://git.kernel.org/pub/scm/utils/dtc/dtc.git/plain/Documentation/dts-format.txt}
\end{frame}

\begin{frame}[fragile]
\frametitle{Example .dts snippet}
\begin{lstlisting}
hello@1 {
  compatible = "virtual,hello", "virtio,hello";
  index = <1>;
};
\end{lstlisting}
\begin{description}
\item[Label] None defined
\item[Node name] hello
\item[Unit address] 1
\item[Property 1]
  \begin{description}
  \item[Name] compatible
  \item[Type] String Array
  \item[Value] ["virtual,hello", "virtio,hello"]
  \end{description}
\item[Property 2]
  \begin{description}
  \item[Name] index
  \item[Type] 32bit Array including 1 Value
  \item[Value] 1
  \end{description}
\end{description}
\end{frame}

\begin{frame}[fragile]
\frametitle{The compatible property}
\begin{lstlisting}
rtc@58 {
    compatible = "maxim,ds1338","microchip,mc1338";
};
\end{lstlisting}
\begin{itemize}
\item List of strings
\item Needed for each node representing a device
\item Used by the kernel to find a proper device driver
\item First string is the Devicename: "<manufacturer>,<model>"
\item Next strings are compatible devices.
\item Used to allow reuse of existing drivers, but allowing exact name.
\item Use manufacturer names from Documentation/devicetree/bindings/vendor-prefixes.txt
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{Addressing}
\begin{lstlisting}
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
    compatible = "arm,cortex-a9";
    reg = <0>;
};
\end{lstlisting}

\begin{itemize}
\item \#address-cells and \#size-cells in the parent node define the format of
      'reg' of the child nodes.
\item in the above example reg uses 1 address cell and no size cell
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{Overwrite values by label}
\begin{lstlisting}
$ cat mynode.dtsi
/ {
  soc {
    pic_3: pic@100 {
      reg = <0x100 0x20 >;
    };
  };
};
\end{lstlisting}

\begin{lstlisting}
$ cat my.dts
#include "my.dtsi"
&pic_3 {
  reg = <0x200 0x30 >;
};
\end{lstlisting}

\begin{lstlisting}
$ dtc -O dts my.dts
/dts-v1/;
/ {
  soc {
    pic_3: pic@100 {
      reg = <0x200 0x30>;
    };
  };
};
\end{lstlisting}
\end{frame}


\begin{frame}
\frametitle{More complex example}
If deeper understanding is required,

\url{https://elinux.org/Device_Tree_Usage}

is a good entry point. Also

\url{https://elinux.org/Device_Tree_Linux}

explains some Linux specific details.
\end{frame}

\begin{frame}[fragile]
\frametitle{Bindings}
The format of all device/bus specific properties are documented:

Documentation/devicetree/bindings
\end{frame}

\subsubsection{Usage}

\begin{frame}[fragile]
\frametitle{Building a DT binary (FDT)}
Out-of-tree with the Device Tree Compiler

Build a FDT by given DTS
\begin{lstlisting}
$ dtc -o my.dtb my.dts
\end{lstlisting}

The Device Tree Compilier is also able to convert a FDT binary back to the
human-readable DTS format:
\begin{lstlisting}
$ dtc -o my.dts my.dtb
\end{lstlisting}
OR in-tree using the Kernel Buildsystem (see next slide)
\end{frame}

\begin{frame}[fragile]
\frametitle{Add a new ARM64 board platform to the kernel}
\begin{lstlisting}
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -318,4 +318,9 @@ config ARCH_ZYNQMP
+config ARCH_MYNEWBOARD
+       bool "My New Board"
+       help
+         This enables support for my new board
+
\end{lstlisting}
\begin{lstlisting}
diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile
--- a/arch/arm64/boot/dts/arm/Makefile
+++ b/arch/arm64/boot/dts/arm/Makefile
@@ -5,3 +5,4 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += \
 dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2f-1xv7-ca53x2.dtb
+dtb-$(CONFIG_ARCH_MYNEWBOARD) += my-new.dtb
\end{lstlisting}
\begin{lstlisting}
diff --git a/arch/arm64/boot/dts/arm/my-new.dts b/arch/arm64/boot/dts/arm/my-new.dts
new file mode 100644
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/my-new.dts
@@ -0,0 +1,16 @@
+/* ARM64 MY BOARD Platform
[..]
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]
\frametitle{Passing FDT to the kernel}
\begin{itemize}
\item statically linked into the kernel
\begin{lstlisting}
# CONFIG_ARM_APPENDED_DTB and CONFIG_ARM_ATAG_DTB_COMPAT
# needs to be enabled
$ cat arch/arm64/boot/Image arch/arm64/boot/dts/arm/my.dtb \
  >> arch/arm/boot/zImage-dtb
\end{lstlisting}
\pause
\item passed to the kernel at boot time\\
The bootloader passes the DTB address through r2
\begin{description}
\item[U-Boot command] boot[mz] <kernel img addr> - <dtb addr>
\item[Barebox variables] bootm.image, bootm.oftree
\end{description}
\pause
\item FIT image - topic for its own, more details in this presentation:\\
      \url{https://elinux.org/images/f/f4/Elc2013_Fernandes.pdf}
\end{itemize}
\end{frame}

\begin{frame}[fragile]
\frametitle{QEMU and FDT}
Dump dtb
\begin{lstlisting}
$ qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -m 512 -smp 2 \
   -device virtio-net-device,netdev=unet \
   -device ivshmem-doorbell,vectors=1,chardev=chid1 \
   -chardev socket,path=/tmp/ivshmem_socket,id=chid1 \
   -kernel /scratch/linux-arm64/arch/arm64/boot/Image \
   -append "console=ttyAMA0 ip=dhcp root=/dev/nfs nfsroot=10.0.2.2:/nfs/debian,nfsvers=3 rw" \
   -machine dumpdtb=my.dtb
\end{lstlisting}
Virtio and ivshmem devices are iteratable.
So they are not dumped into the dtb.

Starting Qemu with a dtb:
\begin{lstlisting}
$ qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic \
   -device virtio-net-device,netdev=unet \
   -device ivshmem-doorbell,vectors=1,chardev=chid1 \
   -chardev socket,path=/tmp/ivshmem_socket,id=chid1 \
   -kernel /scratch/linux-arm64/arch/arm64/boot/Image \
   -dtb /tmp/my.dtb
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]
\frametitle{Match a driver and DT node}
DTS snippet
\begin{lstlisting}
hello@1 {
  compatible = "virtual,hello";
};
\end{lstlisting}
driver source
\begin{lstlisting}
static int hello_probe(struct platform_device *pdev) {
  return 0;
}
static const struct of_device_id hello_match[] = {
  { .compatible = "virtual,hello", }, { }
};
static struct platform_driver hello_driver = {
  .driver = { .name = "hello",
              .owner = THIS_MODULE,
              .of_match_table = hello_match, },
  .probe = hello_probe,
};
static int __init hello_init(void) {
  return platform_driver_register(&hello_driver);
}
module_init(hello_init);
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]
\frametitle{Reading properties in drivers}
DTS snippet
\begin{lstlisting}
hello@1 {
  compatible = "virtual,hello";
  index = <1>;
};
\end{lstlisting}
driver source
\begin{lstlisting}
static int hello_probe(struct platform_device *pdev) {
  int ret;
  u32 value;
  ret = of_property_read_u32(pdev->dev.of_node, "index", &value);
  if (ret < 0)
    pr_err("no index specified\n");
  return ret;
}
\end{lstlisting}
\end{frame}

\begin{frame}[fragile]
\frametitle{Reading DT/OF properties from userspace}
\begin{lstlisting}
$ tree /proc/device-tree
$ cat /proc/device-tree/compatible
OR
$ tree /sys/firmware/devicetree/base
$ cat /sys/firmware/devicetree/base/compatible
\end{lstlisting}
rebuilding DT from user-space:
\begin{lstlisting}
$ dtc -I fs /sys/firmware/devicetree/base -o my.dts
$ dtc -I fs /sys/firmware/devicetree/base -o my.dtb
\end{lstlisting}
\end{frame}

\subsubsection{Linux internals}

\begin{frame}
\frametitle{Source locations}
\begin{description}
\item[DTS files] arch/*/boot/dts/*
\item[Kernel framework] drivers/of/*
\item[Userspace components] 'scripts/dtc' are imported from
     \url{https://git.kernel.org/cgit/utils/dtc/dtc.git}
\item[Docs] Documentation/devicetree
\end{description}
\end{frame}

\subsubsection{Future}
\begin{frame}
\frametitle{Current development}
Device Tree Overlays
\begin{itemize}
\item Needed to support shields.
\item Supported by u-boot, but currently not by the kernel.
\item Status Plumbers Conference '18 \url{https://elinux.org/images/8/86/Overlay_frank.pdf}
\end{itemize}
Device Tree Schema
\begin{itemize}
\item \url{https://elinux.org/images/6/67/Hkg18-120-devicetreeschema-grantlikely-180404144834.pdf}
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Further information}
\begin{itemize}
\item elinux.org Device Tree wiki\\
      \url{https://elinux.org/Device_Tree_Reference}
\item Thomas Petazzoni - Device Tree for Dummies | ELC 2014\\
      \url{https://www.youtube.com/watch?v=uzBwHFjJ0vU}\\
      \url{https://elinux.org/images/f/f9/Petazzoni-device-tree-dummies_0.pdf}
\item \url{https://elinux.org/Device_tree_future}
\item Read 'Documentation/devicetree/bindings/submitting-patches.txt' if you
      consider sending sth. related to DT upstream.
\end{itemize}
\end{frame}

\begin{frame}
\frametitle{Excercise}
\begin{itemize}
\item Extend the hello module to become a platform driver including a
      of match table.
\item Dump the DTB via Qemu and convert it to DTS format.
\item Add a proper node to the DTS
      to trigger the probe function of the hello module.
\item Convert the DTS to DTB format and use it to start Qemu.
\item Check that the hello module is loaded automatically
      and its probe function was called.
\item Add multiple hello nodes to the Device Tree.
      Check how often the init and probe functions are called.
\item Extend the hello module to read a property from the hello DTS node.
\item Add this property to the DTS and check if it's read.
\end{itemize}
\end{frame}

\input{tailpres}