Article directory
Linux system porting: porting the original Kernel to the development board
1. Get the original kernel and compile it
I directly compile the source code provided by the atom, and compile the instructions
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
After compiling, get the image file:
Device tree file:
Second, the kernel boot test
Start the compiled linux kernel from the board through the network, and see the phenomenon. If you want to ping each other through the network, you must be under the LAN!
Set the bootargs parameter of the board uboot to console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw
setenv bootargs console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw
Then copy the generated image file and device tree to the FTP root directory for booting from the network:
cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb ~/linux/tftp/
cp arch/arm/boot/zImage ~/linux/tftp/
input on the development board
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-evk.dtb
bootz 80800000 - 83000000
Start the network, the system starts successfully, you can enter the command:
The root file system we just started is guided by the bootargs environment variable of uboot, where root=/dev/mmcblk1p2 is the guide for the parameters of the root file system to be stored in partition 2 of EMMC. If there is no file system, the startup will fail. Kernel panic caused by missing root filesystem
3. Add your own board file
Add a configuration file for the Punctual Atomic Alpha board
3.1 Board configuration file
Copy the imx_v7_mfg_defconfig configuration file under arch/arm/configs, name it imx_my_emmc_defconfig, the name of our own configuration file, and then modify and configure our own kernel in it
cp arch/arm/configs/imx_v7_mfg_defconfig arch/arm/configs/imx_my_emmc_defconfig
Then you can use
make imx_my_emmc_defconfig
Configure the Linux kernel
3.2 Board Device Tree
Copy a copy of imx6ull-14x14-evk.dts from the directory arch/arm/boot/dts, rename it to imx6ull-my-emmc.dts as the device tree of our own board, and modify it in it later
cp arch/arm/boot/dts/imx6ull-14x14-evk.dts arch/arm/boot/dts/imx6ull-my-emmc.dts
Then in arch/arm/boot/dts/Makefile, find the "dtb-$(CONFIG_SOC_IMX6ULL)" configuration item, add "imx6ull-my-emmc.dtb" to this configuration item and append our device tree, dts will compile generate dtb
3.3 Compile
Modify the previous compilation script
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_my_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
Give the script execution permission, and then execute, the compilation is completed as follows, the compilation is successful The above kernel configuration is no problem
Copy the zImage and device tree .dtb files to the tftp directory, boot from the network, and load our own device tree:
tftp 80800000 zImage
tftp 83000000 imx6ull-my-emmc.dtb
bootz 80800000 - 83000000
Started successfully:
Four, important configuration modification
4.1 Modification of main frequency
Print the CPU frequency on the boot system, and the operating frequency information is stored in /sys/bus/cpu/devices/cpu0/cpufreq
The meaning of the file is as follows:
- cpuinfo_cur_freq : the current cpu operating frequency, the operating frequency read from the CPU register
- cpuinfo_max_freq : The highest operating frequency that the processor can run (unit: KHz)
- cpuinfo_min_freq : The minimum operating frequency that the processor can run (unit: KHz)
- cpuinfo_transition_latency : The time it takes for the processor to switch the frequency (unit: ns)
- scaling_available_frequencies : List of main frequencies supported by the processor (unit: KHz)
- scaling_available_governors : All governor types supported in the current kernel
- scaling_cur_freq : saves the current CPU frequency cached by the cpufreq module, and does not check the CPU hardware registers
- scaling_driver : This file saves the frequency modulation driver used by the current CPU
- scaling_governor : governor (frequency regulation) strategy, there are 5 frequency regulation strategies in the Linux kernel
- Performance, the highest performance, directly use the highest frequency, regardless of power consumption
- Interactive, use the highest frequency directly at the beginning, and then slowly reduce it according to the CPU load
- Powersave, power saving mode, usually runs at the lowest frequency, system performance will be affected, generally do not use this
- Userspace, you can manually adjust the frequency in user space
- Ondemand, check the load regularly, and then adjust the frequency according to the load. Reduce CPU frequency when load is low
- scaling_max_freq : the highest frequency that governor (frequency modulation) can adjust
- cpuinfo_min_freq : The lowest frequency that governor (frequency modulation) can adjust
Print the current frequency: 792M
There are 4 switching frequencies that the CPU can support:
We modify the working frequency and change the default working mode to Powersave mode in the configuration file
sudo vim arch/arm/configs/imx_my_emmc_defconfig
Add default code
Recompile after modification, start the system kernel from the network, and then check the operating frequency of the system, it becomes 198M
In addition to modifying the defconfig file, the method of modifying the working frequency can also be configured graphically, using
make menuconfig
After the graphical configuration, the configuration file is generated, and then compiled. The results of the two methods are the same.
Generally, ondemand mode is used, one can save power, and the other can reduce heat
In addition to the above working frequencies, we can also run the programs we want, and we won't say much about the specific modifications. Generally, we can use the ones provided by the original factory.
4.2 EMMC driver modification
The EMMC in the Linux kernel driver is in 4-wire mode by default, and it is not as fast as 8-wire mode, so we changed the EMMC driver to 8-wire
Modify the EMMC wiring and directly modify the device tree, open the file imx6ull-alientek-emmc.dts, and put the following configuration file
change into
Then compile dts to dtb separately:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
reboot the system
4.3 Network driver modification
The network of the atomic development board is different from the official network hardware of NXP. The network PHY chip is changed from KSZ8081 to LAN8720A. The network driver that comes with the Linux kernel cannot be driven and needs to be modified.
4.3.1 Modify chip reset pin
Open the device tree file imx6ull-my-emmc.dts and find the following code to delete the redundant IO port configuration
After modification:
Delete the following code, let GPIO5_IO07 and GPIO5_IO08 be the reset pins of ENET1 and ENET2 respectively
Then find iomuxc_snvs, configure the two pins just deleted as reset pins, the code is as follows:
4.3.2 Network Clock Pin Configuration
In imx6ull-my-emmc.dts, will be the following two codes
The following parameters are modified to 0x4001b009 (the electrical property values of the two pins)
4.3.3 Modify the pinctrl-0 attribute of a node
Modify the location as follows
Modify these two node attributes to the following figure, and pass in the reset function we wrote above:
4.3.4 Modify network port node and add reset
In the device tree file, the node of fec2 has the address information of the write network port
Modify the value of reg, corresponding to 0 and 1, because the number after ethernet-phy@ is the PHY address, and the PHY address of ENET1 is 0,
so the @ is followed by 0, and the same is true for ENET2:
Add a reset pin in the two fec nodes and set the duration to 200ms for subsequent software reset use
Add driver information to the node to guide the kernel to find the corresponding driver
After the configuration is complete, recompile the device tree
4.3.5 Modify the network driver
Open the drivers/net/ethernet/freescale/fec_main.c file and add the following code to the function fec_probe:
Used to reset the two chips to ensure normal operation, enter the following code to open the graphical interface
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
Enable the network port driver on the interface, the path is as follows
-> Device Drivers
-> Network device support
-> PHY Device support and infrastructure
-> Drivers for SMSC PHYs
If checked, the LAN8720 driver will be compiled
4.3.6 Modify smsc.c file and add soft reset
In Linux, a soft reset of LAN8720A is required to ensure normal operation. The driver file of LAN8720A is drivers/net/phy/smsc.c, you can modify this file and find the smsc_phy_reset reset function inside.
Modified to the following code
//初始化变量
int err, phy_reset;
int msec = 1;
struct device_node *np;
int timeout = 50000;
//获取 FEC1 网卡对应的设备节点
if(phydev->addr == 0) /* FEC1 */
{
np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@02188000");
if(np == NULL)
{
return -EINVAL;
}
}
//获取 FEC2 网卡对应的设备节点
if(phydev->addr == 1) /* FEC2 */
{
np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@020b4000");
if(np == NULL)
{
return -EINVAL;
}
}
//从设备树中获取“phy-reset-duration”属性信息,也就是复位时间
err = of_property_read_u32(np, "phy-reset-duration", &msec);
/* A sane reset duration should not be longer than 1s */
if (!err && msec > 1000)
msec = 1;
//从设备树中获取“phy-reset-gpios”属性信息,也就是复位 IO
phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
if (!gpio_is_valid(phy_reset))
return;
//复位 LAN8720A
gpio_direction_output(phy_reset, 0);
gpio_set_value(phy_reset, 0);
msleep(msec);
gpio_set_value(phy_reset, 1);
//处于 Powerdown 模式的时候才会软复位 LAN8720
int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
if (rc < 0)
return rc;
if ((rc & MII_LAN83C185_MODE_MASK) ==MII_LAN83C185_MODE_POWERDOWN)
{
/* set "all capable" mode and reset the phy */
rc |= MII_LAN83C185_MODE_ALL;
phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
}
phy_write(phydev, MII_BMCR, BMCR_RESET);
/* wait end of reset (max 500 ms) */
do {
udelay(10);
if (timeout-- == 0)
return -1;
rc = phy_read(phydev, MII_BMCR);
} while (rc & BMCR_RESET);
return 0;
After modifying the device tree and the Linux kernel, recompile it, start the Linux kernel, and use the ifconfig command to view the network card
Ping the host, success
4.4 Save the modified configuration file
When modifying the network driver, we enabled the LAN8720A driver through the graphical interface. After enabling, the following code will exist in .config
CONFIG_SMSC_PHY=y
When CONFIG_SMSC_PHY=y, the driver file smsc.c will be compiled. When we execute make clean to clean up the project, the .config file will be deleted, so save the file
- non-graphical
In non-graphical mode, directly rename the generated .config file to the imx_my_emmc_defconfig configuration file and save it to arch/arm/configs
- Graphical
Rename the generated .config file to the imx_my_emmc_defconfig configuration file in the graphical interface and save it to arch/arm/configs
V. Summary of Transplantation
- Get the original kernel source code
- Copy the configuration file, device tree file, compile and download to test whether linux can start
- Modify the configuration file
- Modify the device tree file (important device tree and driver files such as network port, EMMC, serial port, etc., adapt to your own board)
- Compile and generate zImage and device tree files for the development board
- port rootfs
- finish the flower