Post Go back to editing

Multiple Rx DMAs with IIO Drivers

My design uses the ADRV9361-Z7035 SoM running Linux and started from the default HDL reference project. I added custom HDL processing blocks that read data from the ADC FIFO and input to the additional adc_pack blocks that output to additional ADI AXI DMA Controllers. These processing blocks trigger interrupts. I successfully added the additional DMAs to the device tree and regenerated the Boot.bin file using my updated .hdf file. On the Linux side, I see the additional interrupts using "ls -l /proc/interrupts" and I also see the additional DMAs. The problem is I want to be able to react to the specific interrupts and read from that DMA using the iio-rx-dma driver. Currently, the axi-dmac-rx@0 block in the device tree only has one phandle. I tried addition more axi-dmac-rx blocks but Linux wouldn't boot. Do I need to add the other DMA phandles of the dmas line in the axi-dmac-rx block? How can I add drivers to all of my additional DMA controllers? I copied a snippet from my device tree below.

axi_ad9361_adc_dma: dma@7c400000 {
compatible = "adi,axi-dmac-1.00.a";
reg = <0x7c400000 0x10000>;
#dma-cells = <0x1>;
interrupts = <0x0 0x39 0x0>;
clocks = <0x2 0x10>;
linux,phandle = <0xb>;
phandle = <0xb>;
adi,channels {
#size-cells = <0x0>;
#address-cells = <0x1>;

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

axi_ad9361_dac_dma: dma@7c420000 {
compatible = "adi,axi-dmac-1.00.a";
reg = <0x7c420000 0x10000>;
#dma-cells = <0x1>;
interrupts = <0x0 0x38 0x0>;
clocks = <0x2 0x10>;
linux,phandle = <0xd>;
phandle = <0xd>;

adi,channels {
#size-cells = <0x0>;
#address-cells = <0x1>;

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

cf-ad9361-lpc@79020000 {
compatible = "adi,axi-ad9361-6.00.a";
reg = <0x79020000 0x6000>;
dmas = <0xb 0x0>;
dma-names = "rx";
spibus-connected = <0xc>;
};

cf-ad9361-dds-core-lpc@79024000 {
compatible = "adi,axi-ad9361-dds-6.00.a";
reg = <0x79024000 0x1000>;
clocks = <0xc 0xd>;
clock-names = "sampl_clk";
dmas = <0xd 0x0>;
dma-names = "tx";
};

axi_ad9361_adc_dma1: dma@43c10000 {
compatible = "adi,axi-dmac-1.00.a";
reg = <0x43c10000 0x10000>;
#dma-cells = <0x1>;
interrupts = <0x0 0x1e 0x0>;
clocks = <0x2 0x10>;
linux,phandle = <0xaa>;
phandle = <0xaa>;

adi,channels {
#size-cells = <0x0>;
#address-cells = <0x1>;

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

axi_to_lad_0: axi_to_lad@43c20000 {
compatible = "xlnx,axi-to-lad-1.0";
reg = <0x43c20000 0x10000>;
xlnx,s00-axi-addr-width = <0x5>;
xlnx,s00-axi-data-width = <0x20>;
};

axi_ad9361_adc_dma_FIFO_lb: dma@43c30000 {
compatible = "adi,axi-dmac-1.00.a";
reg = <0x43c30000 0x10000>;
#dma-cells = <0x1>;
interrupts = <0x0 0x1f 0x0>;
clocks = <0x2 0x10>;
linux,phandle = <0xab>;
phandle = <0xab>;

adi,channels {
#size-cells = <0x0>;
#address-cells = <0x1>;

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

axi_ad9361_adc_dma_lb: dma@43c40000 {
compatible = "adi,axi-dmac-1.00.a";
reg = <0x43c40000 0x10000>;
#dma-cells = <0x1>;
interrupts = <0x0 0x20 0x0>;
clocks = <0x2 0x10>;
linux,phandle = <0xac>;
phandle = <0xac>;

adi,channels {
      #size-cells = <0x0>;
      #address-cells = <0x1>;

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

axi-dmac-rx@0 {
   compatible = "adi,iio-rx-dma-1.00.a";
   dmas = <0xaa 0x0>;
   dma-names = "rx";
};


Added clarification to the device tree below.
[edited by: dkartis1 at 1:59 AM (GMT -5) on 21 Dec 2020]
  • Hi,

    Sorry for the long wait. If you use a default device tree does Linux start?

    What errors do you get in the boot log ?

    Regards,

    Mircea

  • Hi,

    No worries, I made some updates to the device tree shown below, I referenced one of the add DMACs and created another iio-rx-dma device. Linux boots with this changes and I see the addition iio device using "ls -l /sys/bus/iio/devices."

    In code, I can get the stream device for the addition rx iio device but an additional rx buffer cannot be created using iio_device_create_buffer. After I removed the original Rx buffer, I could get the new iio buffer. Just to verify, it is possible to have multiple rx iio devices with multiple iio buffers when there are the same number of DMACs connected, correct? I believe I need to use the 0xac phandle in the new iio receiver. Let me test that and let you know the results.


    adi,channels {
          #size-cells = <0x0>;
          #address-cells = <0x1>;

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

    axi-dmac-rx@0 {
       compatible = "adi,iio-rx-dma-1.00.a";
       dmas = <0xaa 0x0 0xac 0x0>;
    dma-names = "rx";
     };

    axi-dmac-rx-lb@0 {
       compatible = "adi,iio-rx-dma-1.00.a";
       dmas = <0xab 0x0>;
       dma-names = "rx";
    }
  • Just to verify, it is possible to have multiple rx iio devices with multiple iio buffers when there are the same number of DMACs connected, correct? I believe I need to use the 0xac phandle in the new iio receiver. Let me test that and let you know the results.

    So, right now, an IIO device can have a single IIO buffer.

    If you need multiple IIO buffers, you need to instantiate more IIO devices.

    Similarly, there can be only one DMA instance per IIO buffer.

    The AXI DMA IP core, has a single channel, so that inherently means one DMA per IIO buffer.

    In our reference Linux tree you'll see that for transceivers that have 3 channels (1 TX, 1 RX, 1 ORX) we actually end up creating 3 IIO devices (1 AXI DAC, 2 AXI ADC (with some variations)).

    Inside the HDL these can be represented differently, like a single IP core for everything.

    But in Linux they need to be split logically a bit, based on teh current drivers we have.

    axi-dmac-rx-lb@0 {
       compatible = "adi,iio-rx-dma-1.00.a";
       dmas = <0xab 0x0>;
       dma-names = "rx";
    }

    This compatible string looks unknown to me. We don't seem to have any driver supporting this.

  • This is the iio device driver. I did it the same way as shown in the post below. I'm using a custom driver similar to the post shown below. It works for the axi-dmac-rx dma but having issues with the added axi-dmac-rx-lb dma. I get an error when reading from the buffer for the axi-dmac-rx-lb DMA.

    https://ez.analog.com/linux-software-drivers/f/q-a/97691/is-there-a-simple-driver-example-taking-advantage-of-the-axi-dmac 

    static const struct of_device_id adc_of_match[] = {
    	{ .compatible = "adi,cn0363-adc-1.00.a", .data = &cn0363_chip_info },
    	{ .compatible = "adi,axi-ad9371-obs-1.0",
    				.data = &obs_rx_chip_info },
    	{ .compatible = "adi,m2k-adc-1.00.a", .data = &m2k_adc_chip_info },
    	{ .compatible = "adi,axi-adrv9009-obs-1.0",
    				.data = &obs_rx_chip_info },
    	{ .compatible = "adi,axi-adrv9009-obs-single-1.0",
    				.data = &obs_rx_chip_info },
    	{ .compatible = "adi,axi-adrv9002-rx2-1.0",
    				.data = &adrv9002_rx_chip_info },
    	{ /* end of list */ },

    For my two receive paths, I have 2 ADI AXI DMA controller IP cores and they each feed into separate HP slave interface ports on the Zynq processing system block. The blocks are shown in the image below. I believe this meets what you mentioned for separate IIO devices correct?

    In our reference Linux tree you'll see that for transceivers that have 3 channels (1 TX, 1 RX, 1 ORX) we actually end up creating 3 IIO devices (1 AXI DAC, 2 AXI ADC (with some variations)).

    Looks like I'm having trouble finding the device tree and HDL you mentioned with the 2 AXI ADC, where is this located?

  • Looks like I'm having trouble finding the device tree and HDL you mentioned with the 2 AXI ADC, where is this located?

    The file is here:

    https://github.com/analogdevicesinc/linux/blob/master/arch/arm/boot/dts/zynq-adrv9361-z7035.dtsi

    This is the RX DMA

    https://github.com/analogdevicesinc/linux/blob/master/arch/arm/boot/dts/zynq-adrv9361-z7035.dtsi#L140

    TX DMA:
    https://github.com/analogdevicesinc/linux/blob/master/arch/arm/boot/dts/zynq-adrv9361-z7035.dtsi#L161

    And my bad; there's isn't an ORX channel here.

    I sometimes confuse these variants.


    Essentially, each of those DT blocks should map to an HDL block in your design.

    So, those are the DMA IP cores mapped to DT.

    Then each ADC/DAC IP core maps to a DMA IP core inside the DT.

    The IIO  ADC devices are created in the cf_axI_adc_core.c file.

    Some are created in the ad_adc.c file (there is some duplication that needs cleaning here).

    Then the output IIO DAC devices are created in cf_axi_dds.c

    You can take a look at some other reference designs the 9009 that have 2 ADC paths and one DAC.
    Example:

    https://github.com/analogdevicesinc/linux/blob/master/arch/arm/boot/dts/zynq-zc706-adv7511-adrv9009.dts#L44

    This one has an RX and ORX and a TX.