4. Linux device tree In this section, let's understand about the Linux Device Tree. This is also called as Flattened device tree. We'll just understand, why device tree and what problem it solves. For a time being, let's forget about device tree and let's just pretend that we don't know what it is. Let's say, we have our own custom board, or it could be your Beaglebone hardware. In this board there is a SOC, which is based on ARM architecture and the board has got couple of on board peripherals like the Zigbee transceiver, serial flash, EEPROM, SD card connector, USB interface, etc... And they are connected via the bus interfaces like USART, SPI, I2C, SDIO, USB, etc. In embedded systems, we usually see SPI, I2C, SDIO, UART, USB, etc. Now, the interesting thing here is, the onboard peripherals are not dynamically discoverable. That means, the onboard peripherals which connect to SPI, I2C, SDIO, Ethernet, etc., have no capability to announce their existence on the board by themselves to the operating system like Linux. Why? Because, those interfaces like I2C, SPI, SDIO, etc., they don't have that intelligence to support dynamic discoverability. Even though those peripherals are there on the board, the operating system has no idea about configuring them. But, the USB use these different. When you connect a pen drive or thumb drive to use the port, it has the intelligence to announce its presence to the operating system dynamically by pushing some information. But, these devices cannot do that. All those who cannot announce their presence to the operating system by themselves are called as "Platform devices". That means, USB is not a platform device. Because, it can announce its presence to the operating system using the USB interface. Now the question is, how can we make Linux kernel know about these platform devices or peripherals present on the board. We need to somehow announce their existence to the kernel, since they cannot do it themselves. One solution which we have been using is to go for a static way, that is hard coding these platform device details in a file called the board file. For example, let's say I create a board file for my board and when the kernel calls this function, board_init(), I add each and every platform device to the kernel subsystem with a platform specific data. The platform data is nothing but a data structure which actually describes the peripheral. That's it, there is nothing special about it. Board file is basically the part of the Linux kernel, so when you modify to add new entries, you have to recompile the kernel. Then only your changes will take effect. So, when you add all those platform devices from the board file, Linux comes to know about those platform devices, so then it basically updates a list of all the platform devices present on the board. When the corresponding driver is loaded, the Linux calls the "probe" function of the driver and the platform data will be passed to the driver and the driver will then initialize the peripheral. For example, let's say the name of the platform device zigbee is zigbee100. The corresponding driver name must also be same as the platform device name, that is "zigbee100.ko". When you load this driver, that is "zigbee100.ko", the Linux binds this device with this driver. Linux immediately calls the "probe" function of this driver and the driver will then take care of initializing the peripheral. We'll discuss more about these things later. When you have different boards, each board will have different on board peripherals. That means the boards are not identical. That means, for every board you'll be having one board file. That also means that for each board, you'll be having separate kernel image. So, this kernel image will not run smoothly on this board. This kernel image won't run on these boards. This is a problem which the Linux community wanted to solve. They wanted to cutoff the dependency of platform device enumeration from the Linux kernel. That is hard coding of platform device details into the Linux kernel. Then the ARM community came up with this idea called "Device Tree" also called as "Flattened Device Tree Model". In this case, what they did is, instead of hard coding the hardware details into the Linux kernel board file, every board vendors has to come up with a file called DTS, which stands for "Device Tree Source File" or you can say "Device Tree Structure". This file actually consists of all the details related to the board written using some predefined syntaxes. You can say that this file consists of lots of data structures, which will include all the details of a hardware. It means encoding all the hardware details in a file called DTS. So, every board will have its own DTS file. This file will be compiled using a Device Tree Compiler that we call as DTC. This is one kind of special compiler to convert this DTS file to the stream of bytes, that is nothing but a binary. We call this binary as DTB. The DTB is nothing but a stream of bytes which encodes the details of the hardware, which is derived from DTS compilation. There will be one DTB for every board. When you edit that DTS file to add a new entry, you need not to compile the kernel again and again, you just need to compile the DTS file and get the new DTB. That's it. That means, there are no more board file entries. All the board file entries are now taken over by the DTB. When the kernel boots, you should tell the kernel where this DTB resides in the memory, so that the Linux kernel can load that DTB file and extract all the hardware details of the board. In this case you need not to change the kernel when you change the board but you have to only change the DTB file. This is the idea behind using the DTB. You can go to this path in the Linux kernel and you will see lots of DTB files related to different variation of the board.