Porting Linux to a new board

The scope of the task depends on how similar your board is to an existing development board. In Chapter 3, All About Bootloaders we ported U-Boot to a new board, named Nova, which is based on the BeagleBone Black (when I say based, it actually is one) so, in this case, there are very few changes to the kernel code to be made. If you are porting to completely new and innovative hardware, there will be more to do. I am only going to consider the simple case.

The organization of architecture-specific code in arch/$ARCH differs from one system to another. The x86 architecture is pretty clean because hardware details are detected at runtime. The PowerPC architecture puts SoC and board-specific files in subdirectory platforms. The ARM architecture has the most board and SoC-specific files of all because there are a lot of ARM boards and SoCs. Platform-dependent code is in directories named mach-* in arch/arm, approximately one per SoC. There are other directories named plat-* which contain code common to several versions of an SoC. In the case of the Nova board, the relevant directory is mach-omap2. Don't be fooled by the name, though, it contains support for OMAP2, 3, and 4 chips.

In the following sections, I am going do the port to the Nova board in two different ways. Firstly, I am going to show you how to do this with a device tree, and then without, since there are a lot of devices in the field that fit in this category. You will see that it is much simpler when you have a device tree.

With a device tree

The first thing to do is create a device tree for the board and modify it to describe the additional or changed hardware on the board. In this simple case, we will just copy am335x-boneblack.dts to nova.dts and change the board name:

/dts-v1/;
#include "am33xx.dtsi"
#include "am335x-bone-common.dtsi"
/ {
     model = "Nova";
     compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
  };
...

We can build nova.dtb explicitly:

$ make  ARCH=arm nova.dtb

Or, if we want nova.dtb to be produced by default for the OMAP2 platform with make ARCH=arm dtbs then we could add the following line to arch/arm/boot/dts/Makefile:

dtb-$(CONFIG_SOC_AM33XX) += 
[...]
nova.dtb 
[...]

Now we can boot the same zImage file as before, configured with multi_v7_defconfig, but load the nova.dtb as we can see here:

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 3.18.3-dirty (chris@builder) (gcc version 4.9.1 (crosstool-N
G 1.20.0) ) #1 SMP Wed Jan 28 07:50:50 GMT 2015
[    0.000000] CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] Machine model: Nova
...

We could create a custom configuration by taking a copy of multi_v7_defconfig and adding in those features we need, and cutting down code size by leaving out those we don't.

Without a device tree

Firstly, we need to create a configuration name for the board, in this case, it is NOVABOARD. We need to add this to the Kconfig file of the mach- directory for your SoC and we need to add a dependency for the SoC support itself, which is OMAPAM33XX.

These lines are added to arch/arm/mach-omap2/Kconfig:

config MACH_NOVA BOARD
bool "Nova board"
depends on SOC_OMAPAM33XX
default n

There is a source file named board-*.c for each board, which contains code and configurations which are specific to the target. In our case, it is board-nova.c, based on a copy of board-am335xevm.c. There must be a rule to compile it, conditional on CONFIG_MACH_NOVABOARD, which this addition to arch/arm/mach-omap2/Makefile takes care of:

obj-$(CONFIG_MACH_NOVABOARD) += board-nova.o

Since we are not using the device tree to identify the board, we will have to use the older machine number mechanism. This is a number unique to each board that is passed by the bootloader in register r1, and which the ARM start code will use to select the correct board support. The definitive list of ARM machine numbers is held at: www.arm.linux.org.uk/developer/machines/download.php. You can request a new machine number from: www.arm.linux.org.uk/developer/machines/?action=new#.

If we hijack machine number 4242, we could add it to arch/arm/tools/mach-types, as shown:

machine_is_xxx   CONFIG_xxxx        MACH_TYPE_xxx      number
...
nova_board       MACH_NOVABOARD     NOVABOARD          4242

When we build the kernel, it will be used to create the mach-types.h header file present in include/generated/.

The machine number and the board support are tied together by a structure which is defined like this:

MACHINE_START(NOVABOARD, "nova_board")
/* Maintainer: Chris Simmonds */
.atag_offset    = 0x100,
.map_io         = am335x_evm_map_io,
.init_early     = am33xx_init_early,
.init_irq       = ti81xx_init_irq,
.handle_irq     = omap3_intc_handle_irq,
.timer          = &omap3_am33xx_timer,
.init_machine   = am335x_evm_init,
MACHINE_END

Note that there may be more than one machine structure in a board file, allowing us to create a kernel that will run on several different boards. The machine number passed by the bootloader selects the correct one.

Finally, we need a new default configuration for our board, which selects CONFIG_MACH_NOVABOARD and other configuration options specific to it. In the following example, it would be in arch/arm/configs/novaboard_defconfig. Now you can build the kernel image as usual:

$ make ARCH=arm novaboard_defconfig
$ make -j 4 ARCH=arm CROSS_COMPILE=arm-cortex_a8-linux-gnueabi- zImage

There is still one step before the job is finished. The bootloader needs to be modified to pass the right machine number. Assuming that you are using U-Boot, you need to copy the machine numbers generated by Linux in arch/arm/include/asm/mach-types.h to U-Boot file arch/arm/include/asm/mach-types.h. Then you need to update the configuration header file for Nova, include/configs/nova.h, and add the following line:

#define CONFIG_MACH_TYPE          MACH_TYPE_NOVABOARD

Now, at last, you can build U-Boot and use it to boot the new kernel on the Nova board:

Starting kernel ...

[    0.000000] Linux version 3.2.0-00246-g0c74d7a-dirty (chris@builder) (gcc version 4.9.
1 (crosstool-NG 1.20.0) ) #3 Wed Jan 28 11:45:10 GMT 2015
[    0.000000] CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c53c7d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] Machine: nova_board
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.47.166