bperez77/xilinx_axidma

Missing devicetree entry

AndrejHsk opened this issue · 12 comments

Hello,

I'm working on an Xilinx Zynq device and would like to use your driver for the AXI DMA, in order to be able to interface from a linux application to the logic in the FPGA. I'm currently running the kernel version 4.0 maintained by xilinx under the branch xilinx-v2015.4. The compile process of your driver worked flawlessly. But when trying to insert the module into the running kernel, nothing happens. After some debugging I realised, that the driver is looking for a devicetree entry with the compatible string xlnx,axidma-chrdev. However I cannot find the devicetree entry. Am I missing something? Please help.
Thank you in advance, I'm looking forward to your answer.

Hi,

Apologies, I need to update the README documentation on the main page. In order to use the driver, you need to have at least two device tree entries. The first device tree entry is for the driver itself. This identifies which DMA channels the driver owns and is allowed to use. The other device tree entries are for the AXI DMA channels themselves, which describe the properties of the channel.

I'm going to update the README soon to describe these entries. For now, below is the example device tree nodes you'll need. This corresponds to a single AXI DMA IP on the fabric, with a receive and transmit channel.

/* At top-level of the device tree. */
axidma_chrdev: axidma_chrdev@0 {
    compatible = "xlnx,axidma-chrdev";
    dmas = <&axi_dma_0 0 &axi_dma_0 1>;
    dma-names = "loopback_tx", "loopback_rx";
} ;

/* Should go under the "amba" node in zynq-7000.dtsi. */
axi_dma_0: axidma0@40400000 {
    compatible = "xlnx,axi-dma", "xlnx,axi-dma-6.03.a", "xlnx,axi-dma-1.00.a";
    reg = < 0x40400000 0x10000 >;
    xlnx,include-sg;
    #dma-cells = <1>;

    dma-mm2s-channel@40400000 {
        compatible = "xlnx,axi-dma-mm2s-channel";
        dma-channels = <1>;
        xlnx,datawidth = <64>;
        xlnx,device-id = <0x0>;
        clocks = <&clkc 15>;
        clock-names = "axis";
        interrupt-parent = <&intc>;
        interrupts = < 0 29 4 >;
    } ;
    dma-s2mm-channel@40400000 {
        compatible = "xlnx,axi-dma-s2mm-channel";
        dma-channels = <1>;
        xlnx,datawidth = <64>;
        xlnx,device-id = <0x1>;
        clocks = <&clkc 15>;
        clock-names = "axis";
        interrupt-parent = <&intc>;
        interrupts = < 0 30 4 >;
    } ;
} ;

Excellent, works perfectly. Thank you!

Some small comments though.

For the mentioned kernel branch from xilinx, xilinx-v2015.4, I had to modify your version_portability.h file to include the xilinx_dma.h file from the path linux/amba, instead of linux/dma. Even though it is a 4.0 kernel version, the path in this branch is the old one. With the next branch xilinx-v2016.1 the path linux/dma is correct and the kernel version is 4.4.

I use the xilinx SDK for the generation of the devicetree for my project and the SDK generates for both channels the same entry for xlnx,device-id, so I had to manually change this, so they differ.
My devicetree entries for the AXI DMA and your driver are now the following:

axi_dma_0: dma@80400000 {
            #dma-cells = <1>;
            compatible = "xlnx,axi-dma-1.00.a";
            interrupt-parent = <&intc>;
            interrupts = <0 31 4 0 32 4>;
            reg = <0x80400000 0x10000>;
            dma-channel@80400000 {
                compatible = "xlnx,axi-dma-mm2s-channel";
                interrupts = <0 31 4>;
                xlnx,datawidth = <0x8>;
                xlnx,device-id = <0x0>;
            };
            dma-channel@80400030 {
                compatible = "xlnx,axi-dma-s2mm-channel";
                interrupts = <0 32 4>;
                xlnx,datawidth = <0x8>;
                xlnx,device-id = <0x1>;
            };
        };
axidma_chrdev: axidma_chrdev@0 {
            compatible = "xlnx,axidma-chrdev";
            dmas = <&axi_dma_0 0 &axi_dma_0 1>;
            dma-names = "loopback_tx", "loopback_rx";
        };      

I have no other comments, tried it now with a loopback, mm2s connected to s2mm and the benchmark and transfer examples worked like a charm. Thank you!

Interesting, it's a shame Xilinx wasn't consistent with their 3.x to 4.x version upgrade. Unfortunately, I guess there's no good way to deal with this in general. I'll probably stick with the current version, because the master branch has the newer path.

The only requirement for the "xlnx,device-id" property is that it is unique among all of the DMA channels; it is how the driver differentiates between them. I couldn't ever get device tree generation to work. Is there a guide that you followed that you could point me to? I last tried it with 2015.2.

Glad it worked out for you. Let me know if you have any other questions.

Hi,

sorry for the late reply.

Well basically I follow this guide from Xilinx: http://www.wiki.xilinx.com/Build+Device+Tree+Blob
I have my design in Vivado and I export the hardware including the bitstream to the SDK. I use the Linux kernel version from Xilinx and the device-tree from these sources: http://www.wiki.xilinx.com/Fetch+Sources
I checkout the branch with the kernel version I am interested in and checkout also the same branch for the device-tree, so that the kernel version and the device-tree are identical. Then I follow the guide, add the checked out repository for the device-tree and create the board support package with the device-tree as OS. The option to select the device-tree as OS when creating the board support package becomes available only after the checked out repository with the device-tree is added inside the repositories menu.
Afterwards a window pops up, where I add my bootargs and finish the process of generation.

Sadly there are sometimes some errors in the SDK log but the files are mostly generated ok. For example in the latest SDK 2016.1 using the 2016.1 branches I get errors, when generating my project containing a PCIe IP core, but the device-tree entry gets generated ok. Using the previous branch 2015.4 I get no errors, but the entry for the PCIe core is not functional.
And I always need to modify the entry for the USB, because it does not work at all, when using the generated device-tree. I then go into the kernel repository and take the needed entries from the dts files, which work for my board, which are located in the /arch/arm/boot directory.
Also a good source for the device-tree entries is the bindings directory in the kernel repository located at /Documentation/devicetree/bindings, where you can find example device-tree entries, so you can check if a generated entry from the SDK is valid or not.

So to sum up, the automated generation does not work. You always need to manually adjust the entries. At least that is the case for the mini-itx board, I am working on.

Hello,
I'm working on an Xilinx Zynq device axidma。Now I have achieved one axidma driver and works perfectly. but when I will be two aximdas or more aximdas hung on to the hardware circuit ,I don't know how to modify the devicetree。Please help.
Thank you in advance, I'm looking forward to your answer.

Hi,

I am working with two DMA cores, both only for transmitting data from memory mapped interface to stream interface.
My devicetree entry for these DMA cores is the following:

axi_dma_0: dma@80400000 {
            #dma-cells = <1>;
            compatible = "xlnx,axi-dma-1.00.a";
            interrupt-parent = <&intc>;
            interrupts = <0 30 4>;
            reg = <0x80400000 0x10000>;
            dma-channel@80400000 {
                compatible = "xlnx,axi-dma-mm2s-channel";
                dma-channels = <0x1>;
                interrupts = <0 30 4>;
                xlnx,datawidth = <0x8>;
                xlnx,device-id = <0x0>;
            };
        };
axi_dma_1: dma@80410000 {
            #dma-cells = <1>;
            compatible = "xlnx,axi-dma-1.00.a";
            interrupt-parent = <&intc>;
            interrupts = <0 31 4>;
            reg = <0x80410000 0x10000>;
            dma-channel@80410000 {
                compatible = "xlnx,axi-dma-mm2s-channel";
                dma-channels = <0x1>;
                interrupts = <0 31 4>;
                xlnx,datawidth = <0x8>;
                xlnx,device-id = <0x1>;
            };
        };

The corresponding working entry for the axidma driver is:

axidma_chrdev: axidma_chrdev@0 {
            compatible = "xlnx,axidma-chrdev";
            dmas = <&axi_dma_0 0 &axi_dma_1 0>;
            dma-names = "dma_0_tx", "dma_1_tx";
        };

Here the relevant part is the line "dmas = <&axi_dma_0 0 &axi_dma_1 0>;".
&axi_dma_0 is the label of the first DMA IP core, in my case the DMA at the address 80400000 and the following 0 is the direction of the DMA channel. In my case it is a transmitting channel, so it is a 0. If it was a receiving channel it would be a 1.
The same is for the second DMA IP core at the address 80410000 with the label axi_dma_1.
The line "dma-names = "dma_0_tx", "dma_1_tx";" just gives each available channel a unique name.

If I would have in my two DMA IP cores also the receiving channel, then the axidma devicetree entry could look like this:

axidma_chrdev: axidma_chrdev@0 {
            compatible = "xlnx,axidma-chrdev";
            dmas = <&axi_dma_0 0 &axi_dma_0 1 &axi_dma_1 0 &axi_dma_1 1>;
            dma-names = "dma_0_tx", "dma_0_rx", "dma_1_tx", "dma_1_rx";
        };

Hope this helps you to get it working. Let me know, if you have any other questions.

@AndrejHsk is right in his description. 0 is used for a transmit (CPU -> FPGA) channel, and 1 is used for a receive channel (FPGA -> CPU). I unfortunately still haven't gotten around to updating the docs; I'll do that soon.

If you're hanging, then the typical cause of this is that you've incorrectly specified an interrupt in the device tree. The interrupt is specified in the AXI DMA core device tree entry, with the interrupts property. Don't worry about the first and third number, those will always be the same. The relevant number is the middle number, which specified the interrupt ID for that core.

There's a little bit more to the interrupt ID's, but basically the FPGA's interrupts start at 30 and continue upward. The interrupts aren't completely sequential, there's a skip after a certain number that I can't remember off the top of my head. When you hook up the interrupt lines in your block design the LSB maps to the lowest interrupt number. So, in @AndrejHsk's device tree his first DMA channel is interrupt 30, and the second is 31.

See the documentation (under Documentation/devicetree/bindings/interrupt-controller/interrupts.txt) in the kernel source tree for interrupts in device trees for more information.

Could you post your device tree? That would help me see what the exact issue is.

@AndrejHsk I try two DMA IP cores also the receiving channel , the axidma devicetree entry like this

axidma_chrdev: axidma_chrdev@0 {
            compatible = "xlnx,axidma-chrdev";
            dmas = <&axi_dma_0 0 &axi_dma_0 1 &axi_dma_1 0 &axi_dma_1 1>;
            dma-names = "dma_0_tx", "dma_0_rx", "dma_1_tx", "dma_1_rx";
        };

My devicetree entry for these DMA cores is the following:

        axi_dma_0: axidma0@40400000 {
                        compatible = "xlnx,axi-dma", "xlnx,axi-dma-6.03.a", "xlnx,axi-dma-1.00.a";
                        reg = < 0x40400000 0x10000 >;
                        xlnx,include-sg;
                        #dma-cells = <1>;

                        dma-mm2s-channel@40400000 {
                                        compatible = "xlnx,axi-dma-mm2s-channel";
                                        dma-channels = <1>;
                                        xlnx,datawidth = <64>;
                                        xlnx,device-id = <0x0>;
                                        clocks = <&clkc 15>;
                                        clock-names = "axis";
                                        interrupt-parent = <&intc>;
                                        interrupts = < 0 29 4 >;
                        } ;
                        dma-s2mm-channel@40400030 {
                                        compatible = "xlnx,axi-dma-s2mm-channel";
                                        dma-channels = <1>;
                                        xlnx,datawidth = <64>;
                                        xlnx,device-id = <0x1>;
                                        clocks = <&clkc 15>;
                                        clock-names = "axis";
                                        interrupt-parent = <&intc>;
                                        interrupts = < 0 30 4 >;
                       } ;
               } ;


        axi_dma_1: axidma1@40410000 {
                        compatible = "xlnx,axi-dma", "xlnx,axi-dma-6.03.a", "xlnx,axi-dma-1.00.a";
                        reg = < 0x40410000 0x10000 >;
                        xlnx,include-sg;
                        #dma-cells = <1>;

                        dma-mm2s-channel@40410000 {
                                        compatible = "xlnx,axi-dma-mm2s-channel";
                                        dma-channels = <1>;
                                        xlnx,datawidth = <64>;
                                        xlnx,device-id = <0x0>;
                                        clocks = <&clkc 15>;
                                        clock-names = "axis";
                                        interrupt-parent = <&intc>;
                                        interrupts = < 0 31 4 >;
                        } ;
                        dma-s2mm-channel@40410030 {
                                        compatible = "xlnx,axi-dma-s2mm-channel";
                                        dma-channels = <1>;
                                        xlnx,datawidth = <64>;
                                        xlnx,device-id = <0x1>;
                                        clocks = <&clkc 15>;
                                        clock-names = "axis";
                                        interrupt-parent = <&intc>;
                                        interrupts = < 0 32 4 >;
                       } ;
               } ;

but , when I insmod axidma.ko I find an error

axidma: axidma_of.c: axidma_check_unique_ids: 139: Channels 0 and 2 in the 'dmas' list have the same channel id.

Right, so the device-id property for each channel must be unique. So, under axi_dma_1, your device ids must be something other than 0 and 1. This is how the driver refers to the channels internally and distinguishes betweem them.

@AndrejHsk , Now I get it working 。 I made a mistake 。I revised the following parameters

 dma-mm2s-channel@40410000 {
                xlnx,device-id = <0x2>;
   } ;
  dma-s2mm-channel@40410030 {
               xlnx,device-id = <0x3>;
  } ;

Thank you for your help very much!

Another question ,
If I want to work one DMA , but setting this DMA with multi-channel 。how to modify the devicetree?

The driver doesn't currently have multi-channel support unfortunately. I'm not sure how difficult that would be to add, but I don't think it should be too difficult.

Also note that multi-channel support is only present in Xilinx version 4.x kernels.

I've updated the README to have all the instructions for running the driver. Take a look over it if you can, see if it makes sense and looks OK.