Post Go back to editing

Perform full reset on AD9361 from running Linux (Zynq)

I have a use-case where either,

(1) the AD9361 may go through a hard reset (toggle voltage rail)

(2) the Zynq FPGA may be reloaded while Linux is running (/dev/xdevcfg).

After this I would like to perform whatever necessary steps there are to reset everything needed to use the AD9361 again like the system is coming up out of a fresh boot.

So without doing either (1) or (2) I want to just prove I can reset everything on a working image... I'm trying to follow this older post and hope it is still relevant. The two major issues I have with this are that I can't figure out how to assert the RESETB pin as it it looks to be held up by the ADI driver and I can't seem to unbind the driver following the steps from the linked post :

~/unit_test/support # ls /sys/bus/platform/drivers/dma-axi-dmac/unbind
/sys/bus/platform/drivers/dma-axi-dmac/unbind
~/unit_test/support # echo 7c40000.dma > /sys/bus/platform/drivers/dma-axi-dmac/
unbind
sh: write error: No such device

Attempting to write to the RESETB pin using the GPIO system in Linux I get a "Device or resource busy" error (same when writing to the sync pin). I can write to the EN_AGC pin just fine.

Thanks

Some additional snippets which may/may not be useful

dmesg @ startup :

~/unit_test/support # dmesg | grep ad9361
[    5.762957] ad9361 spi32766.0: ad9361_probe : enter (ad9361)
[    6.040763] ad9361 spi32766.0: ad9361_probe : AD936x Rev 2 successfully initialized
[    7.007410] cf_axi_adc 79020000.cf-ad9361-lpc: ADI AIM (10.00.b) at 0x79020000 mapped to 0xf0bc8000, probed ADC AD9361 as MASTER
[    7.033738] cf_axi_dds 79024000.cf-ad9361-dds-core-lpc: Analog Devices CF_AXI_DDS_DDS MASTER (9.00.b) at 0x79024000 mapped to 0xf0bed000, probed DDS AD9361

relevant dts :

        // https://www.kernel.org/doc/Documentation/devicetree/bindings/dma/adi%2Caxi-dmac.txt
        rx_dma: dma@7c400000 {
                compatible = "adi,axi-dmac-1.00.a";
                reg = <0x7c400000 0x10000>;
                interrupts = <0 59 0>;
                clocks = <&clkc 16>;
                #dma-cells = <1>;
                // adi,channels {
                //     #size-cells = <0>;
                //     #address-cells = <1>;

                //     dma-channel@0 {
                //             reg = <0x0>;
                //             adi,length-width = <0x18>;
                //             adi,source-bus-width = <0x40>;
                //             adi,destination-bus-width = <0x40>;
                //             adi,source-bus-type = <0x2>;
                //             adi,destination-bus-type = <0x0>;
                //     };
                // };
                dma-channel {
                        adi,buswidth = <64>;
                        adi,type = <0>;
                };
        };

        // https://www.kernel.org/doc/Documentation/devicetree/bindings/dma/adi%2Caxi-dmac.txt
        tx_dma: dma@7c420000 {
                compatible = "adi,axi-dmac-1.00.a";
                reg = <0x7c420000 0x10000>;
                interrupts = <0 58 0>;
                clocks = <&clkc 16>;
                #dma-cells = <1>;
                // adi,channels {
                //     #size-cells = <0>;
                //     #address-cells = <1>;

                //     dma-channel@0 {
                //             reg = <0x0>;
                //             adi,length-width = <0x18>;
                //             adi,source-bus-width = <0x40>;
                //             adi,destination-bus-width = <0x40>;
                //             adi,source-bus-type = <0x0>;
                //             adi,destination-bus-type = <0x2>;
                //             adi,cyclic;
                //     };
                // };
                dma-channel {
                        adi,buswidth = <64>;
                        adi,type = <1>;
                        adi,cyclic;
                };
        };

        cf_ad9361_adc_core_0: cf-ad9361-lpc@79020000 {
                compatible = "adi,axi-ad9361-6.00.a";
                reg = <0x79020000 0x6000>;
                dmas = <&rx_dma 0>;
                dma-names = "rx";
                spibus-connected = <&adc0_ad9361>;
                xlnx,dphase-timeout = <0x8>;
                xlnx,num-mem = <0x1>;
                xlnx,num-reg = <0x1>;
                xlnx,s-axi-min-size = <0x1ff>;
                xlnx,slv-awidth = <0x20>;
                xlnx,slv-dwidth = <0x20>;
                xlnx,use-wstrb = <0x0>;
        };

        cf_ad9361_dac_core_0: cf-ad9361-dds-core-lpc@79024000 {
                compatible = "adi,axi-ad9361-dds-6.00.a";
                reg = <0x79024000 0x1000>;
                clocks = <&adc0_ad9361 13>;
                clock-names = "sampl_clk";
                dmas = <&tx_dma 0>;
                dma-names = "tx";
                dac-sample-frequency = <491520000>;
                xlnx,dphase-timeout = <0x8>;
                xlnx,num-mem = <0x1>;
                xlnx,num-reg = <0x1>;
                xlnx,s-axi-min-size = <0x1ff>;
                xlnx,slv-awidth = <0x20>;
                xlnx,slv-dwidth = <0x20>;
                xlnx,use-wstrb = <0x0>;
        };

&adc0_ad9361 {
        en_agc-gpios = <&gpio0 55 0>;
        sync-gpios = <&gpio0 56 0>;
        reset-gpios = <&gpio0 54 0>;
};



added other relevant system info
[edited by: jgutel at 9:22 PM (GMT 0) on 4 May 2020]
  • There RESETB pin is tied to the AD9361 driver, because the driver has all the proper sequence to init the driver within Linux.

    What you want to do, seems to be more along the lines of a no-OS/baremetal driver:

    https://github.com/analogdevicesinc/no-OS/tree/master/ad9361

    That would give you full control, but you also need to manually configure everything.

    One thing that is implemented in the Linux driver though, is a debugfs entry that resets the chip.

    As root:

    cd /sys/kernel/debug/iio

    cd iio:deviceX   [whichever is the ad9361]

    echo 1 > initialize

    This should perform a device reset and reconfigure.

    Not sure when this was the last time it was tested thoroughly, as this is mostly a debug/development feature.

    But the idea still holds.

    This is one of the recommended ways to do this in Linux.

  • Thanks for the reply. Unfortunately I don't have the option to use the baremetal drivers; I have to use Linux for this particular design.

    After reloading the bitstream through xdevcfg (identical bitstream that was on it previously) attempting to initialize results in,

    /sys/kernel/debug/iio/iio:device1 # echo 1 > initialize 
    [  488.266951] ad9361 spi32766.0: Failed to restore state
    [  488.307832] ad9361 spi32766.0: Failed to restore state
    [  488.325433] ad9361 spi32766.0: Failed to restore state
    /sys/kernel/debug/iio/iio:device1 # echo 1 > bist_timing_analysis 
    /sys/kernel/debug/iio/iio:device1 # cat bist_timing_analysis 
    CLK: 30720000 Hz 'o' = PASS
    DC0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:
    0:. . . . . . . . . . . . . . . . 
    1:. . . . . . . . . . . . . . . . 
    2:. . . . . . . . . . . . . . . . 
    3:. . . . . . . . . . . . . . . . 
    4:. . . . . . . . . . . . . . . . 
    5:. . . . . . . . . . . . . . . . 
    6:. . . . . . . . . . . . . . . . 
    7:. . . . . . . . . . . . . . . . 
    8:. . . . . . . . . . . . . . . . 
    9:. . . . . . . . . . . . . . . . 
    a:. . . . . . . . . . . . . . . . 
    b:. . . . . . . . . . . . . . . . 
    c:. . . . . . . . . . . . . . . . 
    d:. . . . . . . . . . . . . . . . 
    e:. . . . . . . . . . . . . . . . 
    f:. . . . . . . . . . . . . . . . 

    As suggested in another thread maybe the only way is to build the driver as a module and rmmod/insmod it before/after to reset it then? In the original question the first code snippet was an attempt to unbind it manually without having to build the driver as a module but that failed with the "No such device" error.

  • We don't typically use kmods. We typically build them as builtins into the kernel.

    rmmod/insmod works if the driver is built as a kmod.

    With some effort, it may work to use this driver as a kmod.

    The bind/unbind method doesn't always work great.

    It could for this driver though.

    I'd go with trying to make 'echo 1 > initialize' work.

  • Any suggestions to that end? Clearly simply using 'echo 1 > initialize' didn't cut it when I tried it. Can you all verify on any board you have by reproducing steps?

    1) load board with standard linux/fw 

    2) reload bitstream through /dev/xdevcfg

    3) 'echo 1 > initialize'

    After thinking about it I decided I'm just going to pull another EMIO pin and OR it with the one that is bound to the driver for asserting the ADI Reset. That way I can still manually hit it from software without mucking with the driver. Hopefully the initialize will then work.

    Update: manually asserting the reset (confirmed with an ILA) didn't change the outcome.

  • Any chance you could verify this works on your end? It's certainly not on mine. Thanks.

  • Has anyone gotten this work? I am having the same exact problem, i need to use the AD9361 after performing an fpga bitstream update while the system is already powered on.

    echo 1 > initialize     did not work for me. I am thinking about modifying the fpga image to give me some control of the RESETB pin from my software. Has anyone had success with this route?

  • @Everyone

    I found a solution that works for me on the zed board using the fmcomms2 project. For other boards it is probably a very similar process. I needed to unbind and then rebind certain drivers to re-initialize the AD9361. Here are the commands I ran:

    echo 79020000.cf-ad9361-lpc > /sys/bus/platform/drivers/cf_axi_adc/unbind
    echo 79024000.cf-ad9361-dds-core-lpc > /sys/bus/platform/drivers/cf_axi_dds/unbind
    echo 7c400000.dma > /sys/bus/platform/drivers/dma-axi-dmac/unbind
    echo 7c420000.dma > /sys/bus/platform/drivers/dma-axi-dmac/unbind
    # PerformFPGA update (fpgautil -b bit.bin)
    echo 7c400000.dma > /sys/bus/platform/drivers/dma-axi-dmac/bind
    echo 7c420000.dma > /sys/bus/platform/drivers/dma-axi-dmac/bind
    echo 79024000.cf-ad9361-dds-core-lpc > /sys/bus/platform/drivers/cf_axi_dds/bind
    echo 79020000.cf-ad9361-lpc > /sys/bus/platform/drivers/cf_axi_adc/bind

    After doing it like this I have a new FPGA image and I can continue to use the AD9361 for transmission ( i am not using for RX and have not tested).

    I needed to do it in this specific order to get it to work properly. I am not sure on other platforms if the exact same commands will work but the idea is similar. There might be more drivers I need to unbind and rebind in case anything else got into a bad state during FPGA update, but I will find those out soon enough.

  •  thank you so much for posting the update with your solution!