This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

WL1801 not initialising in Linux 3.18 on Zynq

Other Parts Discussed in Thread: WL1801

Hi,

We've designed a custom board around the Xilinx Zynq processor including the WL1801. The WL1801 is connected to the Zynq through the SDIO interface. We're trying to bring up the device and not having great success currently. Our Linux image is built using Buildroot and we initially used the TI WL18xx drivers from the Xilinx Linux kernel tree. We couldn't make any progress in bringing up the device with these so switched to using drivers built using instructions on the TI WL18xx Wiki (build-utilities), but again can't seem to get the device working. Here's the information on what we've done.

Building the Drivers

Drivers have been downloaded and built as follows:

git clone git://git.ti.com/wilink8-wlan/build-utilites.git
cd build-utilites
cp setup-env.sample setup-env
gedit setup-env
./build_wl18xx.sh init
./build_wl18xx.sh update R8.6

The last command was failing due to the inclusion of the "__TIMESTAMP__" macro (-Werror=date-time). In order to build successfully we had to make the following change to src/driver/drivers/net/wireless/ti/wlcore/Makefile :

- (echo 'static const char *wlcore_timestamp = __TIMESTAMP__;'; \
+ (echo 'static const char *wlcore_timestamp = "11:54, London, 11-Sep-2015";'; \

Device Tree

I've attached the .dts file to the post. Within it we have a fixed regulator for the enable line of the WL1801 and a wlcore section for device control. We've tried various parameters as seen on other posts on these forums which seem to make no difference at all.

wlcore {
		compatible = "wlcore";
		interrupt-parent = <&gpio0>;
		irq = <11>;
		platform-quirks = <0x1>;
		board-ref-clock = <0x4>;
	};

	wlan_en_reg: fixedregulator@0 {
		compatible = "regulator-fixed";
		regulator-name = "wlan-en-regulator";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
		gpio = <&gpio0 12 4>;
		startup-delay-us = <70000>;
		enable-active-high;
	};


Inserting the Modules

The modules from the build_wl18xx.sh script are inserted post boot on the target in the following order:

insmod /lib/modules/3.18.0-xilinx/updates/compat/compat.ko
insmod /lib/modules/3.18.0-xilinx/updates/net/wireless/cfg80211.ko
insmod /lib/modules/3.18.0-xilinx/updates/net/mac80211/mac80211.ko
insmod /lib/modules/3.18.0-xilinx/updates/drivers/net/wireless/ti/wlcore/wlcore.ko
insmod /lib/modules/3.18.0-xilinx/updates/drivers/net/wireless/ti/wlcore/wlcore_sdio.ko
insmod /lib/modules/3.18.0-xilinx/updates/drivers/net/wireless/ti/wl18xx/wl18xx.ko

After inserting all modules the output from lsmod is as follows:

# lsmod
Module                  Size  Used by    Tainted: G  
wl18xx                 26213  0 
wlcore_sdio             5092  0 
wlcore                122101  1 wl18xx
mac80211              256080  2 wl18xx,wlcore
cfg80211              155802  3 wl18xx,wlcore,mac80211
compat                  6601  4 wl18xx,wlcore_sdio,mac80211,cfg80211
g_ether                 1679  0 
usb_f_rndis            10640  2 g_ether
usb_f_eem               4197  1 
usb_f_ecm_subset        3332  0 
usb_f_ecm               5059  0 
usb_f_ss_lb            11720  0 
u_ether                 8087  5 g_ether,usb_f_rndis,usb_f_eem,usb_f_ecm_subset,usb_f_ecm
libcomposite           29235  6 g_ether,usb_f_rndis,usb_f_eem,usb_f_ecm_subset,usb_f_ecm,usb_f_ss_lb
configfs               16620  7 usb_f_rndis,usb_f_eem,usb_f_ecm_subset,usb_f_ecm,usb_f_ss_lb,libcomposite

After inserting modules trying to set the wlan0 interface to up fails:

# ifconfig wlan0 up
ifconfig: SIOCGIFFLAGS: No such device

There is no visible debug in dmesg indicating any activity from the Kernel Modules apart from:

Loading modules backported from Linux version R8.6-0-g3f5b34f
Backport generated by backports.git R8.6-0-g4677dc3
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Calling CRDA to update world regulatory domain
cfg80211: Exceeded CRDA call max attempts. Not calling CRDA

Have we made any obvious mistakes, or is there anything we're missing? Is there anything else we can try or a way of enabling more debug from the modules?

Thanks in advance.


system.dts.txt
/*
 * CAUTION: This file is automatically generated by Xilinx.
 * Version:  
 * Today is: Fri May 15 13:17:22 2015
*/


/dts-v1/;
/include/ "zynq-7000.dtsi"
/include/ "pl.dtsi"
/ {
	cpus {
		cpu@0 {
			operating-points = <666667 1000000 333334 1000000>;
		};
	};
	chosen {
		bootargs = "console=ttyPS0,115200 mem=0x1fed4000 debug earlyprintk";
	};
	aliases {
		serial0 = &uart1;
		serial1 = &uart0;
	};
	memory {
		device_type = "memory";
		reg = <0x0 0x20000000>;
	};
	gpio-poweroff {
                compatible = "gpio-poweroff";
                gpios = <&gpio0 46 0>;
        };
        framebuffer0: framebuffer@1fed4000 {
                compatible = "simple-framebuffer";
                reg = <0x1fed4000 (480 * 640 * 4)>;
                width = <480>;
                height = <640>;
                stride = <(480 * 4)>;
                format = "x8r8g8b8";
        };


	wlcore {
		compatible = "wlcore";
		interrupt-parent = <&gpio0>;
		irq = <11>;
		platform-quirks = <0x1>;
		board-ref-clock = <0x4>;
	};

	wlan_en_reg: fixedregulator@0 {
		compatible = "regulator-fixed";
		regulator-name = "wlan-en-regulator";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
		gpio = <&gpio0 12 4>;
		startup-delay-us = <70000>;
		enable-active-high;
	};
};
&gpio0 {
	emio-gpio-width = <6>;
	gpio-mask-high = <0x0>;
	gpio-mask-low = <0x5600>;
};
&i2c0 {
	clock-frequency = <400000>;
	status = "okay";
	rtc {
                compatible = "dallas,ds1307";
                reg = <0x68>;
        };
};
&intc {
	num_cpus = <2>;
	num_interrupts = <96>;
};
&qspi {
	is-dual = <0>;
	num-cs = <1>;
	status = "okay";
	xlnx,fb-clk = <0x1>;
        xlnx,qspi-mode = <0x0>;

        flash@0
        {
		compatible = "s25fl512s";
                reg = <0x0>;
                spi-tx-bus-width = <1>;
                spi-rx-bus-width = <4>;
                spi-max-frequency = <100000000>;
                #address-cells = <1>;
                #size-cells = <1>;

                fsbl@0 {
                        label = "fsbl";
                        reg = <0x0 0x500000>;
                };
                kernel@1 {
                        label = "kernel";
                        reg = <0x500000 0x500000>;
                };
                devtree@2 {
                        label = "devtree";
                        reg = <0xA00000 0x40000>;
                };
                ramdisk@3 {
                        label = "ramdisk";
                        reg = <0xA40000 0x18C0000>;
                };
                flash@4 {
                        label = "flash";
                        reg = <0x2300000 0x1D00000>;
                };
        };
};
&sdhci0 {
	clock-frequency = <50000000>;
	status = "okay";
};
&sdhci1 {
	clock-frequency = <50000000>;
	status = "okay";
	vmmc-supply = <&wlan_en_reg>;
};

&spi0 {
	is-decoded-cs = <0>;
	num-cs = <2>;
	status = "okay";
	touchscreen@0 {
                reg = <0>;                                       /* CS0 */
                compatible = "ti,ads7846";
		interrupt-parent = <&gpio0>;
		interrupts = <52 2>;				/* MIO 52, falling edge */
                spi-max-frequency = <1000000>;
                pendown-gpio = <&gpio0 52 0>;
                vcc-supply = <&regulator_vccpint>;              /* dummy */
        };
	nfc@0 {
		compatible = "ti,trf7970a";
		reg = <1>;
		pinctrl-names = "default";
		spi-max-frequency = <2000000>;
		interrupt-parent = <&gpio0>;
		interrupts = <15 1>;				/* GPIO MIO 15, rising edge */
		ti,enable-gpios = <&gpio0 14 0>,
				<&gpio0 13 0>;			/* 13 = dummy- don't need EN2 support */
		vin-supply = <&regulator_vccpint>;              /* dummy */
		autosuspend-delay = <30000>;
		/*irq-status-read-quirk;
		en2-rf-quirk;*/
		status = "okay";
	};
};
&adc {
        status = "disabled";
};
&uart0 {
	current-speed = <115200>;
	device_type = "serial";
	port-number = <1>;
	status = "okay";
};
&uart1 {
	current-speed = <115200>;
	device_type = "serial";
	port-number = <0>;
	status = "okay";
};
&usb0 {
	dr_mode = "peripheral";
	phy_type = "ulpi";
	status = "okay";
	usb-reset = <&gpio0 20 0>;
};
&clkc {
	fclk-enable = <0x3>;
	ps-clk-frequency = <33333333>;
};


  • Hi,

    The dts entries does not look correct.
    Please see: processors.wiki.ti.com/.../WL18xx_Platform_Integration_Guide for the correct dts entries.

    Regards,
    Gigi Joseph.
  • Hi,

    There is a working Zynq build on K3.17 available at http://downloads.architechboards.com/sdk/virtual_machine/download.html. It is the best place I know to start as the zynq interrupt handling is different to a standard ARM processor and so has some Device Tree differences that we don't list.

    Iain

  • Hi Joseph and Iain,

    Thanks for your replies.

    Joseph- I've followed the dts sections on the link you shared. Our DTS is not looking very similar but still not getting any life out of the WL1801. I've attached the latest version.

    Iain - Thanks for the Architech link. I'm currently downloading and will compare the dts in the VM to the one we have to see any obvious mistakes.

    Thanks,


    Siôn

    3386.system.dts.txt
    /*
     * CAUTION: This file is automatically generated by Xilinx.
     * Version:  
     * Today is: Fri May 15 13:17:22 2015
    */
    
    
    /dts-v1/;
    /include/ "zynq-7000.dtsi"
    /include/ "pl.dtsi"
    / {
    	cpus {
    		cpu@0 {
    			operating-points = <666667 1000000 333334 1000000>;
    		};
    	};
    	chosen {
    		bootargs = "console=ttyPS0,115200 mem=0x1fed4000 debug earlyprintk";
    	};
    	aliases {
    		serial0 = &uart1;
    		serial1 = &uart0;
    	};
    	memory {
    		device_type = "memory";
    		reg = <0x0 0x20000000>;
    	};
    	gpio-poweroff {
                    compatible = "gpio-poweroff";
                    gpios = <&gpio0 46 0>;
            };
            framebuffer0: framebuffer@1fed4000 {
                    compatible = "simple-framebuffer";
                    reg = <0x1fed4000 (480 * 640 * 4)>;
                    width = <480>;
                    height = <640>;
                    stride = <(480 * 4)>;
                    format = "x8r8g8b8";
            };
    
    	wlan_en_reg: fixedregulator@2 {
    		compatible = "regulator-fixed";
    		regulator-name = "wlan-en-regulator";
    		regulator-min-microvolt = <3300000>;
    		regulator-max-microvolt = <3300000>;
    		gpio = <&gpio0 12 0>;
    		startup-delay-us = <70000>;
    		enable-active-high;
    	};
    };
    &gpio0 {
    	emio-gpio-width = <6>;
    	gpio-mask-high = <0x0>;
    	gpio-mask-low = <0x5600>;
    };
    &i2c0 {
    	clock-frequency = <400000>;
    	status = "okay";
    	rtc {
                    compatible = "dallas,ds1307";
                    reg = <0x68>;
            };
    };
    &intc {
    	num_cpus = <2>;
    	num_interrupts = <96>;
    };
    &qspi {
    	is-dual = <0>;
    	num-cs = <1>;
    	status = "okay";
    	xlnx,fb-clk = <0x1>;
            xlnx,qspi-mode = <0x0>;
    
            flash@0
            {
    		compatible = "s25fl512s";
                    reg = <0x0>;
                    spi-tx-bus-width = <1>;
                    spi-rx-bus-width = <4>;
                    spi-max-frequency = <100000000>;
                    #address-cells = <1>;
                    #size-cells = <1>;
    
                    fsbl@0 {
                            label = "fsbl";
                            reg = <0x0 0x500000>;
                    };
                    kernel@1 {
                            label = "kernel";
                            reg = <0x500000 0x500000>;
                    };
                    devtree@2 {
                            label = "devtree";
                            reg = <0xA00000 0x40000>;
                    };
                    ramdisk@3 {
                            label = "ramdisk";
                            reg = <0xA40000 0x18C0000>;
                    };
                    flash@4 {
                            label = "flash";
                            reg = <0x2300000 0x1D00000>;
                    };
            };
    };
    &sdhci0 {
    	clock-frequency = <50000000>;
    	status = "okay";
    };
    &sdhci1 {
    	clock-frequency = <50000000>;
    	status = "okay";
    	vmmc-supply = <&wlan_en_reg>;
    	bus-width = <4>;
    	ti,non-removable;
    	ti,needs-special-hs-handling;
    	cap-power-off-card;
    	keep-power-in-suspend;
    
    
    	#address-cells = <1>;
    	#size-cells = <0>;
    	wlcore:wlcore@0 {
    		compatible = "ti,wl1801";
    		reg = <2>;
    		interrupt-parent = <&gpio0>;
    		interrupts = <11 0x4>;
    	};
    };
    
    &spi0 {
    	is-decoded-cs = <0>;
    	num-cs = <2>;
    	status = "okay";
    	touchscreen@0 {
                    reg = <0>;                                       /* CS0 */
                    compatible = "ti,ads7846";
    		interrupt-parent = <&gpio0>;
    		interrupts = <52 2>;				/* MIO 52, falling edge */
                    spi-max-frequency = <1000000>;
                    pendown-gpio = <&gpio0 52 0>;
                    vcc-supply = <&regulator_vccpint>;              /* dummy */
            };
    	nfc@0 {
    		compatible = "ti,trf7970a";
    		reg = <1>;
    		pinctrl-names = "default";
    		spi-max-frequency = <2000000>;
    		interrupt-parent = <&gpio0>;
    		interrupts = <15 1>;				/* GPIO MIO 15, rising edge */
    		ti,enable-gpios = <&gpio0 14 0>,
    				<&gpio0 13 0>;			/* 13 = dummy- don't need EN2 support */
    		vin-supply = <&regulator_vccpint>;              /* dummy */
    		autosuspend-delay = <30000>;
    		/*irq-status-read-quirk;
    		en2-rf-quirk;*/
    		status = "okay";
    	};
    };
    &adc {
            status = "disabled";
    };
    &uart0 {
    	current-speed = <115200>;
    	device_type = "serial";
    	port-number = <1>;
    	status = "okay";
    };
    &uart1 {
    	current-speed = <115200>;
    	device_type = "serial";
    	port-number = <0>;
    	status = "okay";
    };
    &usb0 {
    	dr_mode = "peripheral";
    	phy_type = "ulpi";
    	status = "okay";
    	usb-reset = <&gpio0 20 0>;
    };
    &clkc {
    	fclk-enable = <0x3>;
    	ps-clk-frequency = <33333333>;
    };
    
    
    



  • Hi,

    After the advice on the posts from Joseph and Iain, we've made some progress.

    We found an issue with the Card Detect line on the Zynq which was suppressing all activity from the processor's SDIO1 interface. Once we fixed this we got some more information in the kernel logs. To help diagnose the issue we started to add some trace into the modules in order to get better visbility of what was happening.

    Initially things were failing within wlcore_probe_of() method of wlcore/sdio.c  because the variable np (struct device_node *) was NULL. This is passed into the wlcore_probe_of method by wl1271_probe(). Having read about the TI E2E forums (here specifically ), it looked like someone else had seen this issue and proposed a fix (albeit temporary) where the compatible entry from the .dts is passed into of_find_compatible_node(). This gets us a little further, but then introduces another major issue.

    The next issue encountered is an error requesting time_sync GPIO.

    wlcore: ERROR error requesting time_sync gpio
    wlcore: ERROR can't allocate hw


    Upon investigating the code, we found a line in wlcore/main.c requesting a GPIO to be used for timesync of the WiFi on Pin 66 of the processor. This is hardcoded which worries me a little, and it's also undocumented in any of the hardware integration guides or the datasheet. We have since found that this is a new (undocumented) feature in R8.6 of build-utilities and is meant to be connected to GPIO 11 of the WL1801, even though in the datasheet this is marked as a NC. Due to this we don't have GPIO11 of the WL1801 connected to any GPIO on the Zynq.

    With this in mind, we tried to go back to an older version of the build-utilities and again faced issues. We have tried R8.5 and R8.4, but neither build successfully. They both have errors within them regarding undeclared define's in include/linux/netdevice.h , here' some extracts:

    include/linux/netdevice.h:1242:23: error: 'IFF_MACVLAN' undeclared (first use in this function)
     #define IFF_MACVLAN   IFF_MACVLAN
                           ^
    
    include/linux/netdevice.h:1243:35: error: 'IFF_XMIT_DST_RELEASE_PERM' undeclared (first use in this function)
     #define IFF_XMIT_DST_RELEASE_PERM IFF_XMIT_DST_RELEASE_PERM
                                       ^
    
    include/linux/netdevice.h:1232:27: error: 'IFF_DONT_BRIDGE' undeclared (first use in this function)
     #define IFF_DONT_BRIDGE   IFF_DONT_BRIDGE
                               ^


    Our investigation leads us to a couple of questions:

    1. Why would the variable np in wlcore_probe_of() be NULL when it is passed from wl1271_probe()? Possible .dts issue (.dts is the same as attached to last post)?
    2. How can we work around the GPIO66 Time Sync expectation of the R8.6 driver?
    3. Has anyone else seen the issues encountered in R8.4 and R8.5?
    4. What is the recommended way forward regarding the build-utilities drivers?

  • For the time sync feature I think you can ignore the error. The error condition just skips the starting of a timer and so I think will work fine.
    So, I'd stay on R8.6.Iain
  • Hi Iain,

    Thanks for your prompt reply.

    I forgot to mention that after the TimeSync GPIO Error, the loading of the modules halts as there is a call to kfree().

    /* time sync */
    	wl->time_sync.gpio = 66;
    	ret = gpio_request_one(wl->time_sync.gpio, GPIOF_DIR_OUT, "time_sync");
    	if (ret < 0) {
    		wl1271_error("error requesting time_sync gpio");
    		goto err_buffer_32;
    	}
    ..
    ..
    ..
    ..
    
    err_buffer_32:
    	kfree(wl->buffer_32);

    Thanks,

    Siôn

  • Ok. You'll need to patch out this code in build-utilites/src/driver/drivers/net/wireless/ti/wlcore/main.c as a temporary solution.
    Iain
  • Hi Iain,

    Thanks for the advice. I've patched the offending section of code out and rebuilt. Inserting the modules looks successful and we can see a wlan0 device when doing ifconfig -a! Unfortunately, when I run ifconfig wlan0 up  to set the link up, we get an error regarding RF-Kill:

    # ifconfig wlan0 up
    ifconfig: SIOCSIFFLAGS: Operation not possible due to RF-kill

    Any ideas on this?

    Thanks in advance.

  • what was your full boot log and are you manually inserting the drivers or letting them be inserted upon detection of WL8 based on the depmod -a during installation?
    Iain
  • Hi Iain,

    Some good news!! We finally got the WL1801 module working! We can now bring up the device, connect to networks and transmit and receive data. I'm very grateful for the support on this forum.

    To fix the last issue we removed CONFIG_RFKILL from our kernel build, then all worked OK. Not sure if this is the right thing to do though?!

    Now we have the device up and working, I'd like to ask some questions on what we should do about some of the issues we've faced and have temporarily removed or hard coded:

    1. Running the initial build of the drivers we had an issue where the build was failing due to inclusion of the "__TIMESTAMP__" macro, and we had to substitute the macro for a hard coded. What is the correct way to fix this? Below is the substitution we made.

    src/driver/drivers/net/wireless/ti/wlcore/Makefile
    
    - (echo 'static const char *wlcore_timestamp = __TIMESTAMP__;'; \
    + (echo 'static const char *wlcore_timestamp = "11:54, London, 11-Sep-2015";'; \

    2. The 'compatible' entry from our .dts had to be hardcoded into wlcore/sdio.c/wlcore_probe_of() in order to get past an error in wl1271_probe (as documented here ). What is the correct way to fix this?

    src/driver/drivers/net/wireless/ti/wlcore/sdio.c wlcore_probe_of()
    
    -       if (!np || !of_match_node(wlcore_sdio_of_match_table, np))
    +        if (!np || !of_match_node(wlcore_sdio_of_match_table, np)) {
    +            np = of_find_compatible_node(NULL, NULL, "ti,wl1801");
    +            if (!np)
                     return -ENODATA;
    +        }
    

    3. We had to comment out a section of code relating to time sync in wlcore/main.c/wlcore_alloc_hw() of the R8.6 driver to get the modules to work. This was suggested as a temporary fix, what is the correct fix for this?

    4. In order to bring up the wlan0 interface, we had to completely remove CONFIG_RFKILL from our kernel build. According to the WL18xx Platform Integration Guide (here) CONFIG_RFKILL is a recommended kernel option. Can anyone suggest what we should do here?

    Thanks in advance.

  • Hi Sion,

    1. This behaviour was introduced with gcc 4.9 compiler which now treats that as an error. When we upstreamed R8.6 driver to K4.1 we removed wlcore_timestamp to avoid this.

    2. Only suggestion would be to debug behaviour and see why dts file is not being parsed as expected when it gets to the probe. My guess is that there is perhaps something in the Zynq mmc driver dts handling that prevents the info being passed down correctly to the wlcore driver. So probably just stick to the workaround you have.

    3. We (TI) need to add device tree support for this feature. So stick with what you have

    4. On TI processor Linux builds we have CONFIG_RFKILL=y, so again there is probably some dependency to Zynq kernel and I have no suggestions

    Iain