cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Contributor
Contributor
536 Views
Registered: ‎11-23-2017

Linux VDMA Drivers Not working

Jump to solution

Hello !

I have interfaced CMOS camera with my zynq7020 custom board. I can read the video frames over HDMI port. The vivado hardware design is working fine. I wrote bare-metal drivers in SDK. The system works well.

But now i want to run the system using Linux kernel modulei wrote . but it does not work . 

here is my Linux drivers and bare-metal drivers . With Bare-metal drivers , i can see the video output over HDMI .

First Bare-metal Drivers


int main ()
{
	unsigned int i=0;
   print("---Entering main---\n\r");

      print("\r\n Running AxiVDMASelfTestExample() for axi_vdma_0...\r\n");
   for(i=0;i<1280*720*3;i++){
   Xil_Out8((VIDEO_BASEADDR0 + i), 0);
   Xil_Out8((VIDEO_BASEADDR1 + i+1), 0x00);
   Xil_Out8((VIDEO_BASEADDR2 + i+2), 0x00);
   }

 //  iic_config_init();   //Remove comments for camera output resolution at 640 x 480


   Xil_Out32((FILTER_BASEADDR + 0x010),480);
   Xil_Out32((FILTER_BASEADDR + 0x018),752);
   Xil_Out32((FILTER_BASEADDR + 0x00),129);
   //Default camera Resolution is 752 x 480

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //AXI VDMA S2MM REGISTERS
  Xil_Out32((VDMA_BASEADDR + 0x030), 0x08B);// enable circular mode
   Xil_Out32((VDMA_BASEADDR + 0x03C), 0x0F);
   Xil_Out32((VDMA_BASEADDR + 0x0AC), VIDEO_BASEADDR0); // start address
   Xil_Out32((VDMA_BASEADDR + 0x0B0), VIDEO_BASEADDR1); // start address
   Xil_Out32((VDMA_BASEADDR + 0x0B4), VIDEO_BASEADDR2); // start address
   Xil_Out32((VDMA_BASEADDR + 0x0A8), (1280*3)); //	Screen Resolution Horizontal Length
   Xil_Out32((VDMA_BASEADDR + 0x0A4), (1280*3)); //
   Xil_Out32((VDMA_BASEADDR + 0x0A0),720); //

//AXI VDMA MM2S REGISTERS
   Xil_Out32((VDMA_BASEADDR + 0x000), 0x03); // enable circular mode
   Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0); // start address
   Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR1); // start address
   Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR2); // start address
   Xil_Out32((VDMA_BASEADDR + 0x058), (1280*3)); // 1280 X 720 Resolution
   Xil_Out32((VDMA_BASEADDR + 0x054), (1280*3)); //
   Xil_Out32((VDMA_BASEADDR + 0x050), 720); //


   return 0;
}

Now Equivalent Linux Drivers . ) No Video Output . 

#define DEVICE_NAME   			"AXI_VDMA_DEVICE"
#define CLASS_NAME    			"axi_vdma"
#define VDMA_BASE	 	         0x43000000
//MM2S Registers
#define MM2S_VDMACR                 0x00
#define MM2S_VDMASR                 0x4
#define MM2S_VSIZE                  0x50
#define MM2S_HSIZE                  0x54
#define MM2S_FRMDLY_STRIDE          0x58
#define MM2S_START_ADDRESS0         0x5C
#define MM2S_START_ADDRESS1         0x60
#define MM2S_START_ADDRESS2         0x64
//S2MM Registers
#define S2MM_VDMACR                 0x30
#define S2MM_VDMASR                 0x34
#define S2MM_VSIZE                  0xA0
#define S2MM_HSIZE                  0xA4
#define S2MM_FRMDLY_STRIDE          0xA8
#define S2MM_START_ADDRESS0         0xAC
#define S2MM_START_ADDRESS1         0xB0
#define S2MM_START_ADDRESS2         0xB4

//Frame Buffer Address on DDR (Physical Addresses)
#define Frame_Buffer_Addr0		   	     		//
#define Frame_Buffer_Addr1
#define Frame_Buffer_Addr2

//IMAGE FILTER Physical Addresses
#define IMAGE_FILTER_BASE       0x43C00000
#define IMAGE_FILTER_CONTROL    0x00
#define IMAGE_FILTER_ROWS       0x10
#define IMAGE_FILTER_COLS       0x18


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harry-SJTU");
MODULE_DESCRIPTION("A simple Linux driver for the AXI VDMA.");
MODULE_VERSION("1.0");

static void __iomem *vdma_virt_addr;
static void __iomem *virt_frame_buf_addr;
static void __iomem *image_filter_virt_addr;
unsigned int  length;
static int    message[1024] = {0};
static int    majorNumber;

static struct class*  axivdmaclass  = NULL;
static struct device* axivdmaDevice = NULL;
static int     axi_vdma_open(struct inode *, struct file *);
static int     axi_vdma_release(struct inode *, struct file *);
static ssize_t axi_vdma_read(struct file *, char *, size_t, loff_t *);
static ssize_t axi_vdma_write(struct file *, const char *, size_t, loff_t *);

static int axi_vdma_open(struct inode *inodep, struct file *filep){
   printk(KERN_INFO "AXI VDMA: Device has been opened time(s)\n");
   return 0;
}

static struct file_operations axi_vdma={
.owner=THIS_MODULE,
.open=axi_vdma_open,
.release=axi_vdma_release,
.read=axi_vdma_read,
.write=axi_vdma_write,
};

static int __init axi_vdma_init(void){
// Try to dynamically allocate a major number for the device -- more difficult but worth it
   majorNumber = register_chrdev(0, DEVICE_NAME, &axi_vdma);
   if (majorNumber<0){
      printk(KERN_ALERT "axivdma failed to register a major number\n");
      return majorNumber;
   }
   printk(KERN_INFO "axivdma: registered correctly with major number %d\n", majorNumber);


   // Register the device class
   axivdmaclass = class_create(THIS_MODULE, CLASS_NAME);
   if (IS_ERR(axivdmaclass)){                // Check for error and clean up if there is
      unregister_chrdev(majorNumber, DEVICE_NAME);
      printk(KERN_ALERT "Failed to register device class\n");
      return PTR_ERR(axivdmaclass);          // Correct way to return an error on a pointer
   }

   // Register the device driver
   axivdmaDevice= device_create(axivdmaclass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
   if (IS_ERR(axivdmaDevice)){               // Clean up if there is an error
      class_destroy(axivdmaclass);           // Repeated code but the alternative is goto statements
      unregister_chrdev(majorNumber, DEVICE_NAME);
      printk(KERN_ALERT "Failed to create the device\n");
      return PTR_ERR(axivdmaDevice);
   }

   printk(KERN_INFO "axivdma: device class registered correctly\n");

//request memory region on DDR for Frame Buffers

if(request_mem_region(0x10000000,0x1000000,"axi_vdma_memory")==NULL){
printk("failed to request memory region\n");
}

//MAP Frame BUFFER Memory  (Could be DDR/OCM)
virt_frame_buf_addr = ioremap_nocache(0x10000000,0x1000000);

       if (!virt_frame_buf_addr ) {
                printk("Could not map physical memory to virtual\n");
                return -1;
        }

//INITIALIZE FRAME BUFFER MEMORY TO ZERO
memset_io(virt_frame_buf_addr,0x0,0x1000000);

printk("Frame buffer initialized");

	//MAP AXI IMAGE FILTER BASE ADDRESS
image_filter_virt_addr=ioremap_nocache(IMAGE_FILTER_BASE,124);

if (!image_filter_virt_addr) {
               printk("Could not map Image Filter \n");
               return -1;
        }

iowrite32(129,(void __iomem *)(image_filter_virt_addr + IMAGE_FILTER_CONTROL));

iowrite32(752,(void __iomem *)(image_filter_virt_addr + IMAGE_FILTER_COLS));

iowrite32(480,(void __iomem *)(image_filter_virt_addr + IMAGE_FILTER_ROWS));
//MAP AXI VDMA BASE ADDRESS
vdma_virt_addr=ioremap_nocache(VDMA_BASE,65535);

if (!vdma_virt_addr) {
               printk("Could not map AXI VDMA\n");
               return -1;
        }
// MM2S Registers Configurations

        //START MM2S VDMA
	iowrite32(0x03,(void __iomem *)(vdma_virt_addr + MM2S_VDMACR));
	printk("MM2S CONTROL REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_VDMACR)));

    //Frame Buffer Addr0
    iowrite32(0x10000000,(void __iomem *)(vdma_virt_addr + MM2S_START_ADDRESS0));
	printk("Frame Buffer0 REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_START_ADDRESS0)));

	//Frame Buffer Addr1
	iowrite32(0x102A3000,(void __iomem *)(vdma_virt_addr + MM2S_START_ADDRESS1));
	printk("Frame Buffer1 REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_START_ADDRESS1)));

	//Frame Buffer Addr2
	iowrite32(0x10546000,(void __iomem *)(vdma_virt_addr + MM2S_START_ADDRESS2));
	printk("Frame Buffer2 REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_START_ADDRESS2)));

    //Stride
	iowrite32(1280*3,(void __iomem *)(vdma_virt_addr + MM2S_FRMDLY_STRIDE));
	printk("MM2S Stride REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_FRMDLY_STRIDE)));

    //HSIZE
	iowrite32(1280*3,(void __iomem *)(vdma_virt_addr + MM2S_HSIZE));
	printk("MM2S HSIZE REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_HSIZE)));

    //VSIZE
	iowrite32(720*3,(void __iomem *)(vdma_virt_addr + MM2S_VSIZE));
	printk("MM2S VSIZE REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_VSIZE)));

	// S2MM Registers Configurations

        //START S2MM VDMA
	iowrite32(0x8B,(void __iomem *)(vdma_virt_addr + S2MM_VDMACR));
	printk("S2MM CONTROL REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + S2MM_VDMACR)));

    //Frame Buffer Addr0
    iowrite32(0x10000000,(void __iomem *)(vdma_virt_addr + S2MM_START_ADDRESS0));
	printk("Frame Buffer0 REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + S2MM_START_ADDRESS0)));

	//Frame Buffer Addr1
	iowrite32(0x102A3000,(void __iomem *)(vdma_virt_addr + S2MM_START_ADDRESS1));
	printk("Frame Buffer1 REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + S2MM_START_ADDRESS1)));

	//Frame Buffer Addr2
	iowrite32(0x10546000,(void __iomem *)(vdma_virt_addr + S2MM_START_ADDRESS2));
	printk("Frame Buffer2  REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + S2MM_START_ADDRESS2)));

    //Stride
	iowrite32(1280*3,(void __iomem *)(vdma_virt_addr + S2MM_FRMDLY_STRIDE));
	printk("S2MM Stride REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + S2MM_FRMDLY_STRIDE)));

    //HSIZE
	iowrite32(1280*3,(void __iomem *)(vdma_virt_addr + S2MM_HSIZE));
	printk("S2MM HSIZE REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + S2MM_HSIZE)));

    //VSIZE
	iowrite32(720*3,(void __iomem *)(vdma_virt_addr + MM2S_VSIZE));
	printk("S2MM VSIZE REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_VSIZE)));


	printk("MM2S STATUS REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + MM2S_VDMASR)));
	printk("S2MM STATUS REGISTER %d\n", ioread32((void __iomem *)(vdma_virt_addr + S2MM_VDMASR)));

return 0;

}

//Read Function
static ssize_t axi_vdma_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
    return 0;

}
//Write Function
static ssize_t axi_vdma_read(struct file *filep, char *buffer, size_t len, loff_t *offset){

    return 0;

}

static int axi_vdma_release(struct inode *inodep, struct file *filep){
  printk(KERN_INFO "AXI VDMA: Device successfully closed\n");
  return 0;
}

static void __exit axi_vdma_exit(void){
	device_destroy(axivdmaclass, MKDEV(majorNumber, 0));     // remove the device
   	class_unregister(axivdmaclass);                          // unregister the device class
   	class_destroy(axivdmaclass);                             // remove the device class
   	unregister_chrdev(majorNumber, DEVICE_NAME);             // unregister the major num
	release_mem_region(0x10000000 ,0x1000000);
        printk(KERN_INFO "AXI VDMA Exit\n");
}
module_init(axi_vdma_init);
module_exit(axi_vdma_exit);

Please help to figure out why i can't see the output with my Linux drivers when i run modprobe camera.ko 

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Contributor
Contributor
504 Views
Registered: ‎11-23-2017

there is no node on device tree about HDMI. other video pipe-line components such as Video-In to AXI4 Stream etc. is also not described. becasue it does not take any configurations from CPU . so, HDMI also does not need take any configrutaions/ commands to run. 

View solution in original post

0 Kudos
4 Replies
Highlighted
Teacher
Teacher
526 Views
Registered: ‎06-16-2013

Hi @haroonrl123 

 

Did you use kernel module of HDMI Tx in linux ?

If yes, would you share the result of the following command on linux ?

 

$ ls /sys/devices/platform/amba_pl@0/<your HDMI Tx SS>

 

Best regards,

0 Kudos
Highlighted
Contributor
Contributor
523 Views
Registered: ‎11-23-2017

No . I haven't used HDMI TX module. i am using custom HDMI IP in my hardware design which works and does not need any on-fly configuration. why do i need HDM Tx drivers ?

0 Kudos
Highlighted
Teacher
Teacher
517 Views
Registered: ‎06-16-2013

Hi @haroonrl123 

 

It's my misunderstanding about HDMI Tx.

Did you describe about this driver in device tree blob ?

 

Best regards,

0 Kudos
Highlighted
Contributor
Contributor
505 Views
Registered: ‎11-23-2017

there is no node on device tree about HDMI. other video pipe-line components such as Video-In to AXI4 Stream etc. is also not described. becasue it does not take any configurations from CPU . so, HDMI also does not need take any configrutaions/ commands to run. 

View solution in original post

0 Kudos