cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Visitor
Visitor
1,207 Views
Registered: ‎11-20-2018

AXI timer interrupt in linux

i am using custom made linux by yocto with Zynq Zybo Z7 development board.

and i want to react to the interrupt generated by PL in the linux system.

but have not got any success.

i am using the following vivado design.

Screenshot from 2018-12-11 16-09-03.png

 

the interrupt is connected to PL-PS [0].

 

i am using the following pl.dtsi generated by vivado SDK

/*
 * CAUTION: This file is automatically generated by Xilinx.
 * Version:  
 * Today is: Tue Dec 11 14:06:18 2018
 */


/ {
	amba_pl: amba_pl {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "simple-bus";
		ranges ;
		axi_timer_0: timer@42800000 {
			clock-frequency = <100000000>;
			clock-names = "s_axi_aclk";
			clocks = <&clkc 15>;
			compatible = "xlnx,xps-timer-1.00.a";
			interrupt-names = "interrupt";
			interrupt-parent = <&intc>;
			interrupts = <0 29 4>;
			reg = <0x42800000 0x10000>;
			xlnx,count-width = <0x20>;
			xlnx,gen0-assert = <0x1>;
			xlnx,gen1-assert = <0x1>;
			xlnx,one-timer-only = <0x1>;
			xlnx,trig0-assert = <0x1>;
			xlnx,trig1-assert = <0x1>;
		};
	};
};

and following driver for registering the interrupt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/io.h>

MODULE_LICENSE("GPL");

#define DEVICE_NAME "xilaxitimer"

#define IRQ_NUM		61

#define XIL_AXI_TIMER_BASEADDR 0x41C00000
#define XIL_AXI_TIMER_HIGHADDR 0x41C0FFFF

#define XIL_AXI_TIMER_TCSR_OFFSET		0x0
#define XIL_AXI_TIMER_TLR_OFFSET		0x4
#define XIL_AXI_TIMER_TCR_OFFSET		0x8
#define XIL_AXI_TIMER_CSR_INT_OCCURED_MASK	0x00000100

#define XIL_AXI_TIMER_CSR_CASC_MASK		0x00000800
#define XIL_AXI_TIMER_CSR_ENABLE_ALL_MASK	0x00000400
#define XIL_AXI_TIMER_CSR_ENABLE_PWM_MASK	0x00000200
#define XIL_AXI_TIMER_CSR_INT_OCCURED_MASK	0x00000100
#define XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK	0x00000080
#define XIL_AXI_TIMER_CSR_ENABLE_INT_MASK	0x00000040
#define XIL_AXI_TIMER_CSR_LOAD_MASK		0x00000020
#define XIL_AXI_TIMER_CSR_AUTO_RELOAD_MASK	0x00000010
#define XIL_AXI_TIMER_CSR_EXT_CAPTURE_MASK	0x00000008
#define XIL_AXI_TIMER_CSR_EXT_GENERATE_MASK	0x00000004
#define XIL_AXI_TIMER_CSR_DOWN_COUNT_MASK	0x00000002
#define XIL_AXI_TIMER_CSR_CAPTURE_MODE_MASK	0x00000001

#define TIMER_CNT	0xF8000000

static struct platform_device *pdev;
void *dev_virtaddr;
static int int_cnt;

static irqreturn_t xilaxitimer_isr(int irq,void*dev_id)		
{      
  unsigned int data;
  
  /* 
   * Check Timer Counter Value
   */
  data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCR_OFFSET);
  printk("xilaxitimer_isr: Interrupt Occurred ! Timer Count = 0x%08X\n",data);
  
  /* 
   * Clear Interrupt
   */
  data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
  iowrite32(data | XIL_AXI_TIMER_CSR_INT_OCCURED_MASK,
	    dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
  
  /* 
   * Disable Timer after 100 Interrupts
   */
  int_cnt++;
  
  if (int_cnt>=100)
    {
      printk("xilaxitimer_isr: 100 interrupts have been occurred. Disabling timer");
      data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
      iowrite32(data & ~(XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK),
		dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
    }
  
  return IRQ_HANDLED;
}

static int __init xilaxitimer_init(void)  
{
  unsigned int data;
  
  int_cnt = 0;
  
  printk(KERN_INFO "xilaxitimer_init: Initialize Module \"%s\"\n", DEVICE_NAME);
  
  /* 
   * Register ISR
   */
  if (request_irq(IRQ_NUM, xilaxitimer_isr, 0, DEVICE_NAME, NULL)) {
    printk(KERN_ERR "xilaxitimer_init: Cannot register IRQ %d\n", IRQ_NUM);
    return -EIO;
  }
  else {
    printk(KERN_INFO "xilaxitimer_init: Registered IRQ %d\n", IRQ_NUM);
  }
  
  /* 
   * Map Physical address to Virtual address
   */
  dev_virtaddr = ioremap_nocache(XIL_AXI_TIMER_BASEADDR,
				 XIL_AXI_TIMER_HIGHADDR - XIL_AXI_TIMER_BASEADDR + 1);
  
  /* 
   * Set Timer Counter
   */
  iowrite32(TIMER_CNT,
	    dev_virtaddr + XIL_AXI_TIMER_TLR_OFFSET);
  data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TLR_OFFSET);
  printk("xilaxitimer_init: Set timer count 0x%08X\n",data);
  
  /* 
   * Set Timer mode and enable interrupt
   */
  iowrite32(XIL_AXI_TIMER_CSR_LOAD_MASK,
	    dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
  iowrite32(XIL_AXI_TIMER_CSR_ENABLE_INT_MASK | XIL_AXI_TIMER_CSR_AUTO_RELOAD_MASK,
	    dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

  /* 
   * Register Device Module
   */
  pdev = platform_device_register_simple(DEVICE_NAME, 0, NULL, 0);              
  if (pdev == NULL) {                                                     
    printk(KERN_WARNING "xilaxitimer_init: Adding platform device \"%s\" failed\n", DEVICE_NAME);
    kfree(pdev);                                                             
    return -ENODEV;                                                          
  }
  
  /* 
   * Start Timer
   */
  data = ioread32(dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);
  iowrite32(data | XIL_AXI_TIMER_CSR_ENABLE_TMR_MASK,
	    dev_virtaddr + XIL_AXI_TIMER_TCSR_OFFSET);

  return 0;
} 

static void __exit xilaxitimer_edit(void)  		
{
  /* 
   * Exit Device Module
   */
  iounmap(dev_virtaddr);
  free_irq(IRQ_NUM, NULL);
  platform_device_unregister(pdev);                                             
  printk(KERN_INFO "xilaxitimer_edit: Exit Device Module \"%s\".\n", DEVICE_NAME);
}

module_init(xilaxitimer_init);
module_exit(xilaxitimer_edit);

MODULE_AUTHOR ("Xilinx");
MODULE_DESCRIPTION("Test Driver for Zynq PL AXI Timer.");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("custom:xilaxitimer");

but when i insert the module, i always get the error message that cannot register IRQ 61

root@zybo-zynq7:~# insmod axitimer.ko                                                                                                                                        
xilaxitimer_init: Initialize Module "xilaxitimer"                                                                                                                            
xilaxitimer_init: Cannot register IRQ 61                                                                                                                                     
xilaxitimer_init: Initialize Module "xilaxitimer"                                                                                                                            
xilaxitimer_init: Cannot register IRQ 61                                                                                                                                     
insmod: can't insert 'axitimer.ko': Input/output error

also i do not see any timer message in the boot log

what i am doing wrong?

Tags (4)
0 Kudos
7 Replies
Highlighted
Visitor
Visitor
972 Views
Registered: ‎02-18-2019

 

Most of your code is right. Maybe you can set

#define IRQ_NUM 49

and try again.

q1.jpg

and result is below:

q2.jpg

0 Kudos
Highlighted
Visitor
Visitor
963 Views
Registered: ‎02-18-2019

And you may use platform_get_irq instead of request_irq directly.

0 Kudos
Highlighted
226 Views
Registered: ‎04-29-2019

Hi,

I still cannot get time_irq_drv inside interrupt process.

Please see the below picture.

 

error.png

Device tree is as follow:

/ {
amba_pl: amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
axi_timer_0: timer@42800000 {
clock-frequency = <100000000>;
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-timer-2.0", "xlnx,xps-timer-1.00.a";
interrupt-names = "interrupt";
interrupt-parent = <&intc>;
interrupts = <0 29 4>;
reg = <0x42800000 0x10000>;
xlnx,count-width = <0x20>;
xlnx,gen0-assert = <0x1>;
xlnx,gen1-assert = <0x1>;
xlnx,one-timer-only = <0x1>;
xlnx,trig0-assert = <0x1>;
xlnx,trig1-assert = <0x1>;
};
};
};

Please advise me how to get the irq.

Thanks.

Regards,

Thiha Kyaw

 

0 Kudos
Highlighted
Moderator
Moderator
199 Views
Registered: ‎09-12-2007

Can you not just use  UIO driver with interrupt support. This will handle alot of this for you. 

https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842490/Testing+UIO+with+Interrupt+on+Zynq+Ultrascale

0 Kudos
Highlighted
191 Views
Registered: ‎04-29-2019

Dear Stephenm,

Thank you for your suggestion. Can you share the code sample with interrupt using UIO?
Regards,
Thiha Kyaw
0 Kudos
Highlighted
Moderator
Moderator
185 Views
Registered: ‎09-12-2007

Sure, this below example is for a GPIO. However, it gives a good idea:

https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841623/How+to+debug+Linux+Application+in+SDK+2019.1

0 Kudos
Highlighted
160 Views
Registered: ‎04-29-2019

Hi,

The timer interrupt appears on cat /proc/interrupts.

How can I change the edge type Interrupt? Now it is level interrupt.

Please advise.

Error.png

0 Kudos