Adding RTL8189 WiFi Driver to AM335x-Based Linux
1. Overview of RTL8189
1.1 Introduction to RTL8189
The RTL8189 is a high-performance, low-cost wireless module supporting 802.11b/g/n standards over an SDIO interface (compatible with SDIO 1.1/2.0/3.0). It enables embedded systems to efficiently expand wireless LAN communication capabilities through SDIO hardware interfaces. The module integrates MAC, baseband, and 2.4G RF, achieving speeds up to 150 Mbps while fully conforming to IEEE802.11n Draft 3.0 and IEEE802.11b/g standards. Its optimized RF architecture and baseband algorithms ensure excellent performance and low power consumption.
From a hardware perspective, the RTL8189 uses the AM335x’s MMC2 interface in SDIO mode for data communication and control. Software support includes drivers for operating systems like Linux, Android, and Windows CE, along with support for networking protocols and application tools.
Figure 1 RTL8189 hardware connection diagram
1.2 Hardware Design of RTL8189
The connection between RTL8189 and the host is achieved through SDIO mode. Key connections include:
SDIO_D0~SDIO_D3: Four bidirectional data lines configured for 4-bit data transfer.
SDIO_CMD: Command line for host-to-module communication.
SDIO_CLK: Clock line driven by the host to synchronize the module.
2. Driver Overview
2.1 Software Design
To enable the RTL8189 driver, the Linux kernel must be configured to support SDIO devices. The AM335x processor uses the MMC2 interface for WiFi, while MMC0 is typically reserved for SD cards.
2.2 Kernel Modifications
2.2.1 Initializing MMC2 Pins for RTL8189
Update the mmc0_pin_mux[] array in the board configuration file to include MMC2 pin initialization. Example:
/* Module pin mux for mmc0 */
static struct pinmux_config mmc0_pin_mux[] = {
{"mmc0_dat3.mmc0_dat3", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"mmc0_dat2.mmc0_dat2", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"mmc0_dat1.mmc0_dat1", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"mmc0_dat0.mmc0_dat0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"mmc0_clk.mmc0_clk", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"mmc0_cmd.mmc0_cmd", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"mcasp0_aclkr.mmc0_sdwp", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT_PULLUP},
{"spi0_cs1.mmc0_sdcd", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_a1.mmc2_dat0", OMAP_MUX_MODE3 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_a2.mmc2_dat1", OMAP_MUX_MODE3 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_a3.mmc2_dat2", OMAP_MUX_MODE3 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ben1.mmc2_dat3", OMAP_MUX_MODE3 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_csn3.mmc2_cmd", OMAP_MUX_MODE3 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_clk.mmc2_clk", OMAP_MUX_MODE3 | AM33XX_PIN_INPUT_PULLUP},
{NULL, 0},
};
2.2.2 Adding the MMC Device Interface
Update the am335x_mmc[] array to include MMC2 interface support:
static struct omap2_hsmmc_info am335x_mmc[] __initdata = {
{
.mmc = 1,
.caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = GPIO_TO_PIN(0, 6),
.gpio_wp = GPIO_TO_PIN(3, 18),
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* 3V3 */
},
{
.mmc = 3,
.caps = MMC_CAP_4_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* 3V3 */
// .mmc = 0, /* will be set at runtime */
},
{
.mmc = 0, /* will be set at runtime */
},
{} /* Terminator */
};
static void mmc0_init(int evm_id, int profile)
{
setup_pin_mux(mmc0_pin_mux);
omap2_hsmmc_init(am335x_mmc);
return;
}
/* Beaglebone Rev A3 and after */
static struct evm_dev_cfg beaglebone_dev_cfg[] = {
......
//{mmc0_no_cd_init,DEV_ON_BASEBOARD, PROFILE_NONE},
// {mmc2_wl12xx_init,DEV_ON_BASEBOARD, PROFILE_NONE},
{mmc0_init, DEV_ON_BASEBOARD, PROFILE_NONE},
//{mmc0_no_cd_init,DEV_ON_BASEBOARD, PROFILE_NONE},
{lcdc_init, DEV_ON_BASEBOARD, PROFILE_NONE},
......
}
Notes
These modifications enable RTL8189 initialization during system boot but do not support hot-swapping. For hot-swap support, refer to MMC0's SD card handling logic.
2.3 Driver compilation
The core of this sdio wifi module is rtl8189es, and the platform is TI's AM335x.
According to the provided driver 00001311-RTL8188EUS_RTL8189ES_linux_v4.1.2_4787.20120803.zip, you can also download the latest rtl8189es driver package from Realtek's official website. This driver does not require external firmware.
2.3.1 Configure the kernel
First, you need to configure the kernel to support SDIO devices, support wifi devices, support IEEE 802.11, etc.
2.3.1.1 Support SDIO devices:
Device Drivers --->
<*> MMC/SD/SDIO card support --->
--- MMC/SD/SDIO card support
[ ] MMC debugging
[*] Assume MMC/SD cards are non-removable (DANGEROUS)
[ ] MMC host clock gating (EXPERIMENTAL)
*** MMC/SD/SDIO Card Drivers ***
<*> MMC block device driver
[*] Use bounce buffer for simple hosts
< > SDIO UART/GPS class support
<*> MMC host test driver
*** MMC/SD/SDIO Host Controller Drivers ***
<*> Secure Digital Host Controller Interface support
<*> SDHCI support on the platform specific bus
< > Atmel SD/MMC Driver
<*> TI OMAP Multimedia Card Interface support
<*> TI OMAP High Speed Multimedia Card Interface support
<*> MMC/SD/SDIO over SPI
After the configuration is complete, you can insert an SD card or other SDIO device and check the log information to see whether the kernel supports the SDIO driver. The final result is that the MMC driver can detect the SDIO device.
2.3.1.2 Supported Wi-Fi devices:
Device Drivers --->
[*] Network device support --->
--- Network device support
[*] Wireless LAN --->
*** Enable WiMAX (Networking options) to see the WiMAX drivers *
--- Wireless LAN
<*> IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)
[*] Support downloading firmware images with Host AP driver
[*] Support for non-volatile firmware download
2.3.1.3 Support for IEEE 802.11:
[*] Networking support --->
--- Networking support
-*- Wireless --->
-- Wireless
<*> cfg80211 - wireless configuration API
[ ] nl80211 testmode command
[ ] enable developer warnings
[ ] cfg80211 regulatory debugging
[ ] enable powersave by default
[ ] cfg80211 DebugFS entries
[ ] Old wireless static regulatory definitions
[ ] cfg80211 wireless extensions compatibility
[ ] Wireless extensions sysfs files
-*- Common routines for IEEE802.11 drivers
[ ] lib80211 debugging messages
<*> Generic IEEE 802.11 Networking Stack (mac80211)
......
Recompile the kernel.
2.3.2 Compile the driver
2.3.2.1 Copy the driver source code /driver/rtl8188EUS_rtl8189ES_linux_v4.1.2_4787.20120803.tar.gz of the driver package we provide to the working directory and decompress the source code;
***@driver$ tar zxvf rtl8188EUS_rtl8189ES_linux_v4.1.2_4787.20120803
***@driver$ cd rtl8188EUS_rtl8189ES_linux_v4.1.2_4787.20120803/
2.3.2.2 Select chip type;
Execute ./make_drv:
***@rtl8188EUS_rtl8189ES_linux_v4.1.2_4787.20120803$ ./make_drv
Please select card type(1/2):
1) RTL8188eus
2) RTL8189es
#? 2
You have selected RTL8189es
rtw_version.h has existed!
2.3.2.3 Modify Makefile;
***@rtl8188EUS_rtl8189ES_linux_v4.1.2_4787.20120803$ vim Makefile
Select the main chip model and module interface:
CONFIG_RTL8192C = n
CONFIG_RTL8192D = n
CONFIG_RTL8723A = n
CONFIG_RTL8188E = y
CONFIG_USB_HCI = n
CONFIG_PCI_HCI = n
CONFIG_SDIO_HCI = y
Add the platform type, the default is I386_PC, add CONFIG_PLATFORM_TI_AM335X = y here, and configure all others to n:
CONFIG_PLATFORM_I386_PC = n
CONFIG_PLATFORM_TI_AM335X = y
CONFIG_PLATFORM_ANDROID_X86 = n
CONFIG_PLATFORM_ARM_S3C2K4 = n
CONFIG_PLATFORM_ARM_PXA2XX = n
CONFIG_PLATFORM_ARM_S3C6K4 = n
CONFIG_PLATFORM_MIPS_RMI = n
CONFIG_PLATFORM_RTD2880B = n
CONFIG_PLATFORM_MIPS_AR9132 = n
CONFIG_PLATFORM_RTK_DMP = n
CONFIG_PLATFORM_MIPS_PLM = n
CONFIG_PLATFORM_MSTAR389 = n
CONFIG_PLATFORM_MT53XX = n
CONFIG_PLATFORM_ARM_MX51_241H = n
CONFIG_PLATFORM_ACTIONS_ATJ227X = n
CONFIG_PLATFORM_ARM_TEGRA3 = n
CONFIG_PLATFORM_ARM_TCC8900 = n
CONFIG_PLATFORM_ARM_TCC8920 = n
CONFIG_PLATFORM_ARM_RK2818 = n
CONFIG_PLATFORM_ARM_URBETTER = n
CONFIG_PLATFORM_ARM_TI_PANDA = n
CONFIG_PLATFORM_MIPS_JZ4760 = n
CONFIG_PLATFORM_DMP_PHILIPS = n
CONFIG_PLATFORM_TI_DM365 = n
CONFIG_PLATFORM_MSTAR_TITANIA12 = n
CONFIG_PLATFORM_SZEBOOK = n
CONFIG_PLATFORM_ARM_SUN4I = n
Add CONFIG_PLATFORM_TI_AM1808 related configuration (add after ifeq ($(CONFIG_PLATFORM_I386_PC), y)):
ifeq ($(CONFIG_PLATFORM_TI_AM1808), y)
EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
ARCH := arm
CROSS_COMPILE := arm-arago-linux-gnueabi-
KVER := 3.2.0
KSRC := /home/***/linux/ti-a8-linux-04.06.00.07
Endif
Among them,
EXTRA_CFLAGS: little endian mode;
ARCH: arm platform;
CROSS_COMPILE: cross compiler;
KVER: kernel version number;
KSRC: kernel directory;
Vim command mode "wq" saves Makefile and exits;
2.3.2.4 make
***@rtl8188EUS_rtl8189ES_linux_v4.1.2_4787.20120803$ make
After Make succeeds, 8189es.ko will be generated in the directory, which is the driver we need. Otherwise, if the compilation fails, you need to check whether there is any error in the kernel configuration.
2.3.3 Loading the driver
Copy the driver file 8189es.ko to the development board in a variety of ways (ftp/tftp/usb, etc.). Load the driver via insmode;
root@***:~# insmod 8189es.ko
rtl8189es driver version=v4.1.2_4787.20120803
build time: Apr 11 2013 18:10:15
The driver is loaded successfully, and the SDIO WIFI module is hot-swapped again (if it does not support hot-swap, it must be connected normally before powering on), and the device information appears: root@lierda:~# mmc0: new high speed SDIO card at address 0001
register rtw_netdev_ops to netdev_ops
Chip Version Info: CHIP_8188E_Normal_Chip_TSMC_A_CUT_1T1R_RomVer(0)
......
SetHwReg8188ES: bMacPwrCtrlOn=0
<=CardDisableRTL8188ESdio
<=rtl8188es_hal_deinit
<=== rtw_ips_pwr_down..................... in 40ms
2.3.4 Tool migration
Using ifconfig to view network devices, we can see that there is a wlan0 device (it may be wlan1, wlan2, etc.).
root@***:~# ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 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:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
wlan0 Link encap:Ethernet HWaddr 00:E0:4C:87:00:00
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:1 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)
At this point, the driver porting is complete. After that, you need to port iwlist, wpa_supplicant and other tools for testing.
3. RTL8189 application test
Because most of the current wireless wifi networks are wpa encrypted, it is necessary to port the wpa_supplicant tool.
3.1 Download source code
http://hostap.epitest.fi/wpa_supplicant/
Download wpa_supplicant-0.7.3.tar.gz (openssl uses the patch provided by 0.7.3)
$tar zxvf wpa_supplicant-0.7.3.tar.gz
Download www.openssl.org/source/openssl-0.9.8e.tar.gz
$tar zxvf openssl-0.9.8e.tar.gz
3.2 Compile openssl library
There are two compilation methods, one is static compilation, the final compiled wpa_supplicant is about 2.6M, it does not need dynamic library; the other is dynamic compilation, the final compiled wpa_supplicant is about 1.4M, it needs dynamic library to run.
Patch installation
First, some compilations also require patches. The openssl version we chose is openssl-0.9.8e, so we need to copy wpa_supplicant-0.7.3/patches/openssl-0.9.8e-tls-extensions.patch to the openssl source code;
$ cp wpa_supplicant-0.7.3/patches/openssl-0.9.8e-tls-extensions.patch openssl-0.9.8e/
$ cd openssl-0.9.8e
$ patch -p1 < openssl-0.9.8e-tls-extensions.patch
Note: -p1, here is the number "1".
3.2.1 Dynamic compilation
3.2.1.1 First enter the openssl-0.9.8e directory;
cd openssl-0.9.8e/
3.2.1.2 Through the config configuration file;
./config shared --prefix=/home/***/openssl no-asm
3.2.1.3 Modify Makefile (- for removing settings, + for adding new settings);
$ vi Makefile
- CC= cc
+ CC= arm-none-linux-gnueabi-gcc
- AR= ar $(ARFLAGS) r
+ AR= arm-none-linux-gnueabi-ar $(ARFLAGS) r
- RANLIB= /usr/bin/ranlib
+ RANLIB= arm-none-linux-gnueabi-ranlib
Note: My CPU is Pentium series, so there are 3 "-march=pentium" in the Makefile generated by config, and the compilation will fail, so I need to delete all 3 places here:
3.2.1.4 make and make install;
$ make
$ make install
In this way, the ssl library is installed under /home/***/openssl/;
3.2.1.5 Copy the following library files to /usr/lib in the development board;
libssl.so.0.9.8
libcrypto.so.0.9.8
3.2.2 Static compilation
3.2.2.1 First enter the openssl-0.9.8e directory;
cd openssl-0.9.8e/
3.2.2.2 Same as dynamic compilation, but here Configure is used to configure compilation options;
$./Configure linux-elf-arm -DL_ENDIAN
linux:'arm-none-linux-gnueabi-gcc' shared
--prefix=/home/***/openss
3.2.2.3 Modify Makefile (- means removing settings, + means adding new settings);
$ vi Makefile
- CC= cc
+ CC= arm-none-linux-gnueabi-gcc
- AR= ar $(ARFLAGS) r
+ AR= arm-none-linux-gnueabi-ar $(ARFLAGS) r
- RANLIB= /usr/bin/ranlib
+ RANLIB= arm-none-linux-gnueabi-ranlib
3.2.2.4 make并make install;
$ make
$ make install
In this way, the ssl library is installed under /home***/openssl/;
3.2 Compile wpa_supplicant
Enter the wpa_supplicant-0.7.3/wpa_supplicant directory generated by decompressing wpa_supplicant-0.7.3.tar.gz:
$cp defconfig .config
$vim .config
# Uncomment following two lines and fix the paths if
you have installed OpenSSL
# or GnuTLS in non-default location
#CFLAGS += -I/usr/local/openssl/include
#LIBS += -L/usr/local/openssl/lib
CC=arm-arago-linux-gnueabi-gcc -L
/home/***/openssl/lib/
CFLAGS += -I/home/***/openssl/include
LIBS += -L/home/***/openssl/lib
$make
After successful compilation, three executable tools will appear in the wpa_supplicant directory:
wpa_supplicant, wpa_passphrase, wpa_cli, copy them to the development board.
Copy the wpa_supplicant.conf file to /etc of the development board:
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="ARM-TEST"
scan_ssid=1
key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
pairwise=TKIP CCMP
group=CCMP TKIP WEP104 WEP40
psk="********"
}
4. Test wpa_supplicant
First, turn on a wireless router and set the name "ARM-TEST" and password "********", which is consistent with the configuration file wpa_supplicant.conf;
Execute wpa_supplicant in the development board;
wpa_supplicant v0.7.3
Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> and contributors
usage:
wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] [-g<global ctrl>] \
-i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
[-b<br_ifname>] [-f<debug file>] \
[-o<override driver>] [-O<override ctrl>] \
[-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
[-p<driver_param>] [-b<br_ifname>] ...]
...
example:
wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf
Finally, a usage example will appear. Enter the command on the development board:
wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf &
& indicates background running.
After the connection is successful, you can check the router interface to see that the connection is successful and statically configure the IP, such as:
$ ifconfig wlan0 192.168.1.10
$ ping 192.168.1.1
Ping result is returned successfully, and the test is completed.
Add routing table information;
$ route add -net 192.168.1.0 netmask 255.255.255.0 gw 192.168.1.1 dev wlan0
$ route add default gw 192.168.1.1
Add DNS in /etc/resolv.conf and set it according to the actual network settings:
$ vi /etc/resolv.conf
nameserver 202.101.172.46
nameserver 8.8.8.8
After successful configuration, ping Baidu test:
$ ping www.baidu.com
PING www.baidu.com (115.239.210.26): 56 data bytes
64 bytes from 115.239.210.26: seq=0 ttl=55 time=17.672 ms
64 bytes from 115.239.210.26: seq=1 ttl=55 time=27.143 ms
--- www.baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 17.672/22.407/27.143 ms
wpa_supplicant wireless test successful.
As an official partner of TI, Vixinco has been specializing in TI MPU processors for many years. Our AM335x SOM is an industrial-grade SOM designed based on TI AM335x processor. It is widely used in various industrial scenarios. How many wifi modules can be adapted? If you have any needs, please feel free to inquire.