Marvel 88W8686 SDIO WiFi Integration
Add chip code files to target file system
Marvell should have supplied the 88W8686 chip code files with the hardware. These files need to be copied to target file system, with a minor file rename. The driver expects to find these files in /lib/firmware on the target file system.
mkdir -p $DEVDIR/fs/overlay/lib/firmware cp /tmp/helper_sd.bin $DEVDIR/fs/overlay/lib/firmware/sd8686_helper.bin cp /tmp/sd8686.bin $DEVDIR/fs/overlay/lib/firmware files="$DEVDIR/fs/overlay/lib $DEVDIR/fs/overlay/lib/firmware $DEVDIR/fs/overlay/lib/firmware/sd8686_helper.bin $DEVDIR/fs/overlay/lib/firmware/sd8686.bin" svn add $files svn ci -m "Added code images for 88W8686 chipset" $files
Enable kernel drivers
Configure the kernel so there variable are set as follows:
CONFIG_LIBERTAS=m CONFIG_LIBERTAS_SDIO=m CONFIG_MMC=y CONFIG_MMC_DAVINCI=y
Enable helper applications
Configure the Wifi tools so they get built.
CONFIG_FS_APPS_WIRELESS_TOOLS=y CONFIG_FS_APPS_WPASUPPLICANT=y
SD8686 as a WiFi client
Runtime driver module loading
Boot target hardware without wifi module installed. Install module. You should see:
mmc0: new SDIO card at address 0001
or
mmc1: new SDIO card at address 0001
depending on which SD slot is used.
Verifying Marvel 88W8686 chip properly detected
On a DM365, the following entries should exist in sysfs.
For SD slot 0:
cd /sys/devices/platform/davinci_mmc.0/mmc_host/mmc0/mmc0:0001/mmc0:0001:1 echo class: `cat class`, vendor: `cat vendor`, device: `cat device`
For SD slot 1:
cd /sys/devices/platform/davinci_mmc.1/mmc_host/mmc1/mmc1:0001/mmc1:0001:1 echo class: `cat class`, vendor: `cat vendor`, device: `cat device`
The output should be:
class: 0x07, vendor: 0x02df, device: 0x9103
Verifying SDIO hardware interface configuration
The debugfs file system contains entries that contain the current settings for the MMC/SD/SDIO interface of interest.
mount -t debugfs none /sys/kernel/debug cat /sys/kernel/debug/mmc0/ios cat /sys/kernel/debug/mmc1/ios
Installing Libertas WiFi module
modprobe libertas
Output will only be generated if there is an error.
Installing Libertas SDIO module
modprobe libertas_sdio helper_name=/lib/firmware/sd8686_helper.bin fw_name=/lib/firmware/sd8686.bin
You should see:
Libertas SDIO driver libertas_sdio: Copyright Pierre Ossman libertas_sdio mmc0:0001:1: firmware: requesting /lib/firmware/sd8686_helper.bin libertas_sdio mmc0:0001:1: firmware: requesting /lib/firmware/sd8686.bin libertas: 00:19:88:3d:d3:77, fw 9.70.3p36, cap 0x00000303 libertas: wlan0: Marvell WLAN 802.11 adapter
If you don't see any output, you may need to increase the printk debug level:
echo 8 > /proc/sys/kernel/printk
or you can look in the kernel message buffer
dmesg | tail -n 6
Verifying wlan0 exists
Make sure Linux network interface and wireless LAN interface are both found
ifconfig wlan0 iwconfig wlan0
You should get output like:
wlan0 Link encap:Ethernet HWaddr 00:19:88:3D:D3:77 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)
and for iwconfig, the output will be similar to:
wlan0 IEEE 802.11b/g ESSID:"" Mode:Managed Frequency:2.412 GHz Access Point: Not-Associated Bit Rate:0 kb/s Tx-Power=15 dBm Retry short limit:8 RTS thr=2347 B Fragment thr=2346 B Encryption key:off Power Management:off Link Quality:0 Signal level:0 Noise level:0 Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0 Tx excessive retries:0 Invalid misc:0 Missed beacon:0
Power on WiFi sub-system
ifconfig wlan0 up
No output will be generated if successful.
Scan for access points
iwlist wlan0 scan
which lists access points that are in range, like:
wlan0 Scan completed : Cell 01 - Address: 00:12:25:57:61:B5 ESSID:"Hawley" Mode:Managed Frequency:2.462 GHz (Channel 11) Quality=97/100 Signal level=-28 dBm Noise level=-96 dBm Encryption key:off Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s 24 Mb/s; 36 Mb/s; 54 Mb/s; 6 Mb/s; 9 Mb/s 12 Mb/s; 48 Mb/s
Attaching WiFi to access point
Security disabled
iwconfig wlan0 essid "Hawley"
WEP security
iwconfig wlan0 essid "Hawley" iwconfig wlan0 key 0001020304
WPA security
mkdir -p /etc/wpa_supplicant cat <<EOF >/etc/wpa_supplicant/wpa_supplicant.conf # Example wpa_supplicant network={ ssid="Baily" psk="very secret passphrase" priority=5 } EOF wpa_supplicant -d -iwlan0 -c/etc/wpa_supplicant/wpa_supplicant.conf -Dwext &
With debug output enabled, you will have lots of information on what is not working if you run into a problem.
Verifying access point association
You can check you are associated with an access point using
iwconfig wlan0
With example output being:
wlan0 IEEE 802.11b/g ESSID:"Baily" Mode:Managed Frequency:2.437 GHz Access Point: 00:13:10:EA:BD:66 Bit Rate:1 Mb/s Tx-Power=13 dBm Retry short limit:8 RTS thr=2347 B Fragment thr=2346 B Encryption key:<too big> Security mode:open Power Management:off Link Quality=95/100 Signal level=-44 dBm Noise level=-89 dBm Rx invalid nwid:0 Rx invalid crypt:121 Rx invalid frag:0 Tx excessive retries:6 Invalid misc:13 Missed beacon:0
If you are having trouble associating with an access point, I find connecting to the AP with my laptop is a good way to verify the AP is configured as expected.
Configuring IP networking
ifconfig wlan0 10.111.0.157 route add -net 0.0.0.0 gw 10.111.0.1 netmask 0.0.0.0 dev wlan0 route -n
With example output:
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 10.111.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 10.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 wlan0 0.0.0.0 10.111.0.1 0.0.0.0 UG 0 0 0 wlan0 0.0.0.0 10.111.0.1 0.0.0.0 UG 0 0 0 eth0
Note that the routing table is traversed from top to bottom, so packets for the Internet will go out wlan0 since that entry is closer to the top.
Functional test
The Google nameserver, which supports ping, is at IP address 8.8.8.8.
ping -c 5 8.8.8.8
Unconfiguring WiFi client mode of operation
ifconfig wlan0 down rmmod libertas_sdio rmmod libertas
SD8686 as a WiFi access point
Patch kernel
The following approach patches the SDIO IRQ handler is such a way that operation can switch between wifi client and micro access point by unloading and reloading drivers. The patch that came with the Marvell uap code broke wifi client mode of operation.
0) static struct sdio_driver sdio_uap points to uap_io_probe() and uap_io_remove() -- uap_io.c
1) uap_io_probe() get struct sdio_func *func -- uap_io.c
2) func-> card is struct mmc_card -- sdio_func.h
3) func -> card -> host is struct mmc_host -- include/linux/mmc/card.h
4) In struct mmc_host there is a back pointer to the card host -> card -- include/linux/mmc/host.h
5) card -> quirks in struct mmc_card allows unique aspects of a card to be recorded
6) The line that gets changed in drivers/mmc/core/sdio_irq.c
- if (host->caps & MMC_CAP_SDIO_IRQ) + if ((host->caps & MMC_CAP_SDIO_IRQ) && (host->card->cis.vendor != MARVELL))
instead of testing card vendor against MARVELL, we can use quirks
+ if ((host->caps & MMC_CAP_SDIO_IRQ) && (!(host->card->quirks & MMC_QUIRK_SLOW_IRQS)))
7) Need to define MMC_QUIRK_SLOW_IRQ_PROCESSING in include/linux/mmc/card.h
#define MMC_QUIRK_SLOW_IRQS (1<<1) /* wait until all pending irqs processed before enabling irqs again */
8) in uap_io_probe() in uap_io.c, we can have really ugly code that mungs all the layers and records the quirk
+ if (func->card != NULL) + func->card->quirks |= MMC_QUIRK_SLOW_IRQ_PROCESSING; + else + printk(KERN_WARN " Unable to adjust SD8686 card handling properties\n");
ret = sdio_claim_irq(func, uap_io_interrupt);
9) in uap_io_remove(), unrecord quirk
sdio_claim_host(uapcard->func); + if (func->card != NULL) + func->card->quirks &= ~MMC_QUIRK_SLOW_IRQ_PROCESSING; sdio_release_irq(uapcard->func);
Load modules
cd /lib/modules/2.6.32-17-ridgerun/extra insmod uapio.ko insmod uap8xxx.ko helper_name=/lib/firmware/sd8686_helper.bin fw_name=/lib/firmware/sd8686_ap.bin
Start station
Adjust the access point configuration by editing the /etc/uaputl.conf file. Instructions in $DEVDIR/proprietary/sd8686-uap/src/uap_src/README.
uaputl sys_config /etc/uaputl.conf uaputl bss_start
Using another computer you should see Marvell Micro AP SSID as an available access point. You can monitor the access point using
uaputl sys_config uaputl sta_list
Problems and how to fix them
uap_main.c error: struct net_device has no member named open
When building micro access point, you get a
sd8686-uap/src/uap_src/uap/uap_main.c:1460: error: 'struct net_device' has no member named 'open'
libertas: unable to identify card model
If installing the Libertas SDIO module produces
libertas_sdio: Libertas SDIO driver libertas_sdio: Copyright Pierre Ossman libertas: unable to identify card model
and the output of dmesg contains:
SDIO: ignoring broken CISTPL_VERS_1 mmc0: new SDIO card at address 0001 libertas enter: lbs_init_module() libertas leave: lbs_init_module() libertas enter: if_sdio_init_module() libertas_sdio: Libertas SDIO driver libertas_sdio: Copyright Pierre Ossman libertas enter: if_sdio_probe() libertas: unable to identify card model libertas leave: if_sdio_init_module(), ret 0
You likely need a kernel patch.
davinci_mmc davinci_mmc.1: data write CRC error
When SD8686 SDIO card is inserted into the mmc1 slot on the TI DM365 EVM, the following error is reported
mmc1: new SDIO card at address 0001 libertas_sdio mmc1:0001:1: firmware: requesting /lib/firmware/sd8686_helper.bin davinci_mmc davinci_mmc.1: data write CRC error libertas: failed to load helper firmware libertas_sdio: probe of mmc1:0001:1 failed with error -84
Solution to the problem unknown at this time.
Testing with hardware with one SD slot
If you can have u-boot active and remove the SD memory card, you can load and boot the kernel over the network, if that is available.
setenv bootargs2 console=ttyS0,115200n8 mem=99M root=/dev/nfs nfsroot=10.111.0.4:/local/home/tfischer/work/p/fs/fs rw ip=dhcp setenv setargs setenv bootargs \${bootargs2} ; setenv autostart no ; setenv autoload no ; dhcp ; setenv t 'setenv serverip 10.111.0.4 ; tftp 0x82000000 kernel.uImage.tfischer.p.leo365 ; run setargs ; bootm 0x82000000' ; run t