This post explains how to cross-compile the Linux kernel and Backport driver sources against ARM platform and loading the binaries to the target. The end users who are interested in bringing up their target with linux kernel with wlan drivers might find this blog helpful.
What is Backporting in Linux?
The backports is a separate Linux project. "Backporting" aims to backport current Linux upstream device drivers for use with older kernels. Refer Linux wiki page for more documentation. The Linux backports project is a set of patches/scripts/sources that allows us to generate a backport package.
This blog post picks up Cypress's FMAC backport package and compiles them against ARM platform.
Why we need Backports ?
The objective is to provide a central mechanism for backporting the device drivers of any subsystem, thereby enabling both users and developers to always focus on upstream Linux kernel development. This means that one can stay in old kernel version and still can use the latest drivers from mainline so as to support the latest features.
Note that the backport shall have limitation on the minimum kernel version running on the target. For instance, the backport driver source with version v4.12 need atleast linux kernel version v3.0+ for backporting to work fine. Check the Cypress's readme files in backport sources for the related information.
Setup the toolchain for cross-compiling the linux kernel(against ARM) and device drivers to the target platform.
This blog has following sections.
Setting up cross toolchain for ARM
Contact the Cypress customer support to gain access to the Cypress's FMAC package (Backport driver sources).
$ sudo apt-get install libc6-armel-cross libc6-dev-armel-cross binutils-arm-linux-gnueabi libncurses5-dev gcc-arm-linux-gnueabi u-boot-tools lzop
The Linux kernel image and driver modules shall be built separately. Below is the example using iMX6UL platform running linux kernel 4.1.15 interfacing 43430 WLAN chip. The instructions provided here should be the same for iMX6SX platform.
The high level goal of the following "Build Linux Kernel" section is to generate a kernel image with CONFIG_CFG80211 and CONFIG_BCMDHD being configured in different way as mentioned below, while all others steps are standard steps to build an iMX image.
Build Linux Kernel
1. Get the Linux kernel source from freescale git repository and extract the source.
Git clone/download the correct linux kernel source by referring the git tag from Freescale git - refs/tags/rel_imx_4.1.15_2.1.0_ga
$ tar zxvf linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.gz
2. Set up build environment and kernel configuration
$ cd linux-imx-rel_imx_4.1.15_2.1.0_ga
Make sure to run following commands in full privileged mode, as "distclean" would require admin permission to clear all the last configured files. The "distclean" takes care of deleting all the configs and files that need to be deleted for clean build.
$ sudo -s
$ make distclean
Configure the kernel against iMX platform. Both iMX6UL and iMX6SX platforms use imx_v7_defconfig.
The kernel configuration will be written to ".config" file.
$ make ARCH=arm imx_v7_defconfig
3. Now, edit .config and build cfg80211 as module (as shown below). The CONFIG_BCMDHD is not needed as part of kernel, as FMAC driver is used for WLAN configuration in this case. The CONFIG_CFG80211=m will let kernel know that this is a driver module and it won't get compiled with the kernel build. The driver modules has to be built explicitly.
CONFIG_CFG80211=m
CONFIG_BCMDHD=n
4. Build the Linux kernel image(uImage). Pass ARCH=arm and CROSS_COMPILE=arm-linux-gnueabi- so as to cross-compile against ARM platform using the toolchain "arm-linux-gnueabi-". The LOADADDR is a platform dependent value and this indicates the start address of kernel image. Check the Board files from vendor and set accordingly. The address 0x10008000 is the LOADADDR for iMX6UL platform. (Note: LOADADDR=0x80800000 for iMX6SX platform)
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- uImage LOADADDR=0x10008000
5. The kernel image is available in the following folder after successful build.
Path to kernel image: arch/arm/boot/zImage
Please refer to the attached file (kernel_logs) which gives some help commands to cross check the build arguments set correctly for toolchain before build.
Build kernel driver module
Get the Cypress's backport driver sources available from Cypress FMAC package: Cypress Linux FMAC (Orga)
1. Download and untar the linux backports package
$ tar zxvf cypress-backports-*.tar.gz
$ cd *backports/
2. (Native) compile local tools and generate .config. Export the MY_KERNEL to point to the target linux kernel to compile the drivers against it.
$ MY_KERNEL=<4.1.15 kernel path>
Generate the .config using "defconfig-brcmfmac" which will set all necessary configurations for FMAC driver. The driver configuration will be written to ".config" file.
$ make KLIB=$MY_KERNEL KLIB_BUILD=$MY_KERNEL defconfig-brcmfmac
3. Cross compile the kernel modules. This command will start the build and generate the driver modules. As mentioned in above section, build the FMAC driver modules explicitly by passing "modules" with the make command.
$ make KLIB=$MY_KERNEL KLIB_BUILD=$MY_KERNEL ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules
4. The following files are generated after successful build.
compat/compat.ko
net/wireless/cfg80211.ko
drivers/net/wireless/broadcom/brcm80211/brcmutil/brcmutil.ko
drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko
Build Device tree -- (Skip this section if .dtb file for target is already available)
Get the Cypress's device tree available from Cypress FMAC package: Cypress Linux FMAC (Orga)
1. Untar the Cypress devicetree package.
$ tar zxvf cypress-devicetree-*.tar.gz
2. Find your board's dtb file, for example
cypress-devicetree/iMX6SX/4.1.15/imx6sx-sdb-btwifi-fmac.dtb
(Note: If your board's dtb is not available in the cypress devicetree package, please refer to the available dts/dtsi files and create them for your board, then compile them for the dtb file. iMX dts files are located in linux-imx/arch/arm/boot/dts/ folder of the Linux kernel tree. Below command compiles a dts file)
$ make ARCH=arm
Find attached to this post "fmac_wl_dtb", the DTBs for iMX6UL and iMX6SX platforms.
Load the DTB, Kernel image, WLAN firmware and drivers
1. Copy the zImage and dtb files to the target board. Set the build args TARGET_IP with the IP address of the target board. Make sure the target board has internet access via wired/wireless connectivity and reachable to the build machine. Use "scp" to transfer the files from build machine to target.
$ TARGET_IP=
$ scp
$ scp
2. Copy firmware files to the target board and rename the filename as per chip name(Example: brcmfmac43430-sdio.bin where 43430 is chip name). Create "/lib/firmware/brcm" directory if not already present on target.
$ tar zxvf cypress-firmware*.tar.gz
$ scp
3. Copy your nvram file (from board vendor) to the target board and rename it as per chip name (Example: brcmfmac43430-sdio.txt)
$ scp
4. Extract the attached "fmac_wl_dtb" and find the "wl_fmac_imx" user utility and copy to the target. This user-space utility is used to configure WLAN chip, associate to SSID, perform scan and get scan results, etc.
$ scp wl_fmac_imx root@$TARGET_IP:/bin/.
5. Copy Cypress kernel modules which was compiled in previous steps (compat.ko, cfg80211.ko, brcmfmac.ko, and brcmutil.ko ) to the target.
$ scp
6. Reboot the target. Press ctrl-c to enter u-boot and configure it to load with new kernel image. Update the board environment variables to use the correct kernel image and device-tree file. Save and reset the target.
U-Boot command:
=> env print image fdt_file
=> setenv image zImage_cy
=> setenv fdt_file cy.dtb
=> saveenv
=> env print image fdt_file
Before "reset", connect the wifi dongle to the target.
=> reset
7. Check the updated kernel version using "uname -a". Boot up the target board with the above zImage and insmod the following driver modules.
$ insmod /lib/modules/
$ insmod /lib/modules/
$ insmod /lib/modules/
$ insmod /lib/modules/
8. Check the new wlan interface "wlan0" created in "ifconfig" menu.
$ ifconfig
eth0 Link encap:Ethernet HWaddr 00:04:9F:04:0C:EE
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
..
..
wlan0 Link encap:Ethernet HWaddr 00:90:4C:2A:0A:00
inet6 addr: fe80::290:4cff:fe2a:a00/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:652 (652.0 B)
9. Check the kernel logs by "dmesg". Check the FMAC firmware version and the logs showing "wlan0" which is the new interface created in "ifconfig".
$ dmesg | tail
brcmfmac: brcmf_c_preinit_dcmds: Firmware version = wl0: Nov 14 2017 18:47:34 version 13.10.271 (TOB) (r674299 WLTEST) FWID 01-c46a1839
brcmfmac: brcmf_c_preinit_dcmds: CLM version = API: 18.2 Data: 9.10.0 Compiler: 1.36.1 ClmImport: 1.34.1 Creation: 2017-11-14 18:45:42
IPv6: ADDRCONF(NETDEV_UP): wlan0: link is not ready
10. Give full permission for "wl" utility since this will be used for any wlan configuration or getting wlan status.
$ chmod +x /bin/wl_fmac_imx
11. End users prefer to use wpa_supplicant and wpa_cli commands to configure WLAN. The supplicant uses a global configuration file. The following example is based on a minimal configuration file which let supplicant to join a SSID with open network. Refer to: WPA_Supplicant page for more details on advanced supplicant configuration.
ctrl_interface=/var/run/wpa_supplicant
ctrl_interface_group=0
update_config=1
network={
ssid="XX"
key_mgmt=NONE
}
$ wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf -B
$ wpa_cli
wpa_cli v2.5
Copyright (c) 2004-2015, Jouni Malinen
This software may be distributed under the terms of the BSD license.
See README for more details.
Selected interface 'wlan0'
Interactive mode
> status
bssid=xx:xx:xx:xx:xx:xx
freq=2417
ssid=XX
id=0
mode=station
pairwise_cipher=NONE
group_cipher=NONE
key_mgmt=NONE
wpa_state=COMPLETED
ip_address=x.x.x.x
address=xx:xx:xx:xx:xx:xx
uuid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
> scan_results
bssid / frequency / signal level / flags / ssid
xx:xx:xx:xx:xx:xx 2417 -69 [ESS] XX
> disconnect
OK
<3>CTRL-EVENT-DISCONNECTED bssid=xx:xx:xx:xx:xx:xx reason=3 locally_generated=1
> status
wpa_state=DISCONNECTED
ip_address=x.x.x.x
address=xx:xx:xx:xx:xx:xx
uuid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
> reconnect
OK
<3>CTRL-EVENT-SCAN-STARTED
<3>CTRL-EVENT-SCAN-RESULTS
<3>WPS-AP-AVAILABLE
<3>Trying to associate with SSID 'XX'
<3>Associated with xx:xx:xx:xx:xx:xx
<3>CTRL-EVENT-CONNECTED - Connection to xx:xx:xx:xx:xx:xx completed [id=0 id_str=]
12. Obtain IP address from access point.
$ udhcpc -i wlan0
$ ifconfig
..
..
wlan0 Link encap:Ethernet HWaddr 00:90:4C:2A:0A:00
inet addr:192.168.43.249 Bcast:192.168.43.255 Mask:255.255.255.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:3 errors:0 dropped:0 overruns:0 frame:0
TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:702 (702.0 B) TX bytes:1772 (1.7 KiB)
(Note: the DHCP client could be different for different platforms)
原文链接:Getting started on Linux Driver Backporting - FMAC