element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Avnet Boards Forums
  • Products
  • Dev Tools
  • Avnet Boards Community
  • Avnet Boards Forums
  • More
  • Cancel
Avnet Boards Forums
Software Application Development DTS syntax and interrupts from PL under Linux
  • Forum
  • Documents
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Avnet Boards Forums to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • State Not Answered
  • Replies 4 replies
  • Subscribers 329 subscribers
  • Views 1121 views
  • Users 0 members are here
Related

DTS syntax and interrupts from PL under Linux

Former Member
Former Member over 12 years ago

Is there a quick-start guide anywhere on DTS syntax that describes how to hard-code user PL peripherals into the DTS file? Specifically, I'm trying to get an interrupt from the PL to the PS in Linux, and there seems to be barely any information out there about doing this, but what little I've found makes reference to modifying the DTS file. I've also seen references to a function "request_irq()" with regards to the Zynq chip running Linux, but strangely, this function does not seem to be part of the ARM libraries in SDK. Has anyone succeeded in implementing something like this?

  • Sign in to reply
  • Cancel
Parents
  • bhfletcher
    0 bhfletcher over 12 years ago

    A DTS tutorial was just posted by the Xillinux people.  It might be helpful.

    http://www.zedboard.org/node/529

     

    Bryan

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Former Member
    0 Former Member over 12 years ago in reply to bhfletcher

    The following entry can be made to the DTS to add an AXI Timer with an interrupt attached to it.  This will attach interrupt 84 in XPS to the GIC.  84 was the number that XPS assigned when I connected the interrupt.  You have to subtract 32 from that number.

    ttmytimer {
    tttcompatible = "dglnt,mytimer-1.00.a";
    tttinterrupt-parent = <&ps7_scugic_0>;
    tttinterrupts = < 0 52 4 >;
    tttreg = <0x42800000 0x10000>;
    tt};


    You can then add the following code to the probe function of the device driver.


    t/* Register the interrupt */
    tirq = platform_get_irq(pdev, 0);
    tif (irq >= 0) {
    ttreturnVal = request_irq(irq, timer_irq_handler, 0, pdev->name, pdev);
    ttif (returnVal != 0) {
    tttdev_info(&pdev->dev, "Interrupt Registered.
    ");
    tttgoto err_irq;
    tt}
    t}


    t// Configure Interrupt Rate
    tiowrite32( SECOND_1,
    tt   base_addr + 1);

    tregVal = ioread32(base_addr + 1);
    tdev_info(&pdev->dev, "Loaded with value of %d
    ", regVal);

    t/* Turn on the timer */
    tiowrite32( TCSR_EINT_M |
    tt   TCSR_ENT_M  |
                       TCSR_ARHT_M |
    tt   TCSR_MODE_GEN_M |
                       TCSR_UDT_DOWN_M,
    tt   base_addr);


    Then you need to fill in the handler for the IRQ

    static irqreturn_t timer_irq_handler(int irq, void *dev_id)
    {
    tstruct platform_device *pdev = dev_id;
    tu32 regVal;

    tdev_info(&pdev->dev, "ECE453 PL Timer IRQ received.
    ");
    tregVal =ioread32(base_addr);
    tdev_info(&pdev->dev, "ECE453 Control Value: 0x%08x
    ", regVal);
    tregVal =ioread32(base_addr+1);
    tdev_info(&pdev->dev, "ECE453 LoadValue: %d
    ", regVal);
    t
    tregVal =ioread32(base_addr);
    tregVal |= TCSR_INT_M ;
    tiowrite32( regVal ,
    tt   base_addr);

    treturn IRQ_HANDLED;
    }

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
Reply
  • Former Member
    0 Former Member over 12 years ago in reply to bhfletcher

    The following entry can be made to the DTS to add an AXI Timer with an interrupt attached to it.  This will attach interrupt 84 in XPS to the GIC.  84 was the number that XPS assigned when I connected the interrupt.  You have to subtract 32 from that number.

    ttmytimer {
    tttcompatible = "dglnt,mytimer-1.00.a";
    tttinterrupt-parent = <&ps7_scugic_0>;
    tttinterrupts = < 0 52 4 >;
    tttreg = <0x42800000 0x10000>;
    tt};


    You can then add the following code to the probe function of the device driver.


    t/* Register the interrupt */
    tirq = platform_get_irq(pdev, 0);
    tif (irq >= 0) {
    ttreturnVal = request_irq(irq, timer_irq_handler, 0, pdev->name, pdev);
    ttif (returnVal != 0) {
    tttdev_info(&pdev->dev, "Interrupt Registered.
    ");
    tttgoto err_irq;
    tt}
    t}


    t// Configure Interrupt Rate
    tiowrite32( SECOND_1,
    tt   base_addr + 1);

    tregVal = ioread32(base_addr + 1);
    tdev_info(&pdev->dev, "Loaded with value of %d
    ", regVal);

    t/* Turn on the timer */
    tiowrite32( TCSR_EINT_M |
    tt   TCSR_ENT_M  |
                       TCSR_ARHT_M |
    tt   TCSR_MODE_GEN_M |
                       TCSR_UDT_DOWN_M,
    tt   base_addr);


    Then you need to fill in the handler for the IRQ

    static irqreturn_t timer_irq_handler(int irq, void *dev_id)
    {
    tstruct platform_device *pdev = dev_id;
    tu32 regVal;

    tdev_info(&pdev->dev, "ECE453 PL Timer IRQ received.
    ");
    tregVal =ioread32(base_addr);
    tdev_info(&pdev->dev, "ECE453 Control Value: 0x%08x
    ", regVal);
    tregVal =ioread32(base_addr+1);
    tdev_info(&pdev->dev, "ECE453 LoadValue: %d
    ", regVal);
    t
    tregVal =ioread32(base_addr);
    tregVal |= TCSR_INT_M ;
    tiowrite32( regVal ,
    tt   base_addr);

    treturn IRQ_HANDLED;
    }

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
Children
  • Former Member
    0 Former Member over 12 years ago in reply to Former Member

    Hi dear,
    we are also doing similar kind of this. we are using zedboard. In FPGA we are generating interrupt on line 91 and in arm under linux we are trying to catch the interrupt.

    for this i have written a kernel module to catch the interrupt. in this module, interrupt on line 91 is properly getting registered. but unfortunately i am not getting any print messages in irq_handler.

    the following is my module code:

    #include <linux/module.h>    /* Needed by all linux kernel driver modules */
    #include <linux/kernel.h>    /* Needed for KERN_INFO */
    #include <linux/cdev.h>        /* provides cdev struct, how the kernel represents char devices internally */

    // just sorta added:
    #include <linux/init.h>
    #include <linux/fs.h>
    #include <linux/irq.h>
    #include <linux/of.h>
    #include <linux/of_address.h>
    #include <linux/of_irq.h>
    #include <linux/interrupt.h>
    #include <asm/io.h>


    #define MAJOR_NUM 35
    #define DEVICE_NAME "gpio"

    static int irq;  // the virtual irq number that will be requested from open firmware
    // static test_hw_map *module_register;
    static struct cdev timer_intr_cdev;

    /* IRQ HANDLER */
    static irqreturn_t timer_intr_irq_handler(int irq, void *dev_id) {
        printk(KERN_ERR "printk err timer_intr - in the irq handler!
    ");
        pr_err("pr_err timer_intr - in the irq handler!
    ");
        return IRQ_HANDLED;
    }


    /* FILE SYSTEM OPERATIONS */
    static int timer_intr_open(struct inode *inode, struct file *file) {
        printk(KERN_INFO "timer_intr_open: successful
    ");
        return 0;
    }
    struct file_operations timer_intr_fops = {
        .open  =    timer_intr_open,
    };

    /* LOADING/UNLOADING DRIVER FUNCTIONS */
    /* init function is run when driver is added to kernel */
    static int __init timer_intr_init(void) {
        struct irq_data *data;t
        struct device_node *np = NULL;
        int result, hw_irq;
        struct resource resource;

        unsigned long *virt_addr;
        unsigned int startAddr;

        // check how to get output
        printk(KERN_INFO "timer_intr init
    ");
       
        np = of_find_node_by_name(NULL, "gpio");
        if (!np) {
            printk(KERN_ERR "gpio: can't find compatible node in this kernel build");
            return -ENODEV;
        } else {
            result = of_address_to_resource(np, 0, &resource);
            if (result < 0) {
                return result;
            }
            printk(KERN_INFO "gpio: reg. size=%d Bytes
    ", (u32)resource.end - (u32)resource.start);
            startAddr = (unsigned int)resource.start;
           
            // get a virtual irq number from device resource struct
            irq = of_irq_to_resource(np, 0, &resource);
            if (irq == NO_IRQ) {
                printk(KERN_ERR "gpio: of_irq_to_resource failed...
    ");
                of_node_put(np);
                return -ENODEV;
            }
            printk(KERN_INFO "gpio: virq=%d
    ", irq);
            // check the hw irq is correct
    tdata = irq_get_irq_data(irq);
            hw_irq = WARN_ON(!data)?0:data->hwirq;
            printk(KERN_INFO "gpio: hw_irq=%d
    ", hw_irq);
           

            if(register_chrdev(MAJOR_NUM,"gpio",&timer_intr_fops))
            {   
    ttprintk(KERN_ERR "gpio: cannot register /dev/gpio
    ");
    ttreturn -ENODEV;
    t}
            // map the physical address of the timer into the virtual address space
            virt_addr = of_iomap(np, 0);
            printk(KERN_INFO "timer at 0x%08X mapped to 0x%08X
    ", startAddr, (u32)virt_addr);
           
            // install the irq handler
           
            result = request_irq(irq, timer_intr_irq_handler, IRQF_DISABLED, "gpio", NULL);
            if (result < 0) {
                printk(KERN_ERR "unable to request IRQ%d : %d
    ", irq, result);
                of_node_put(np);
                return -ENODEV;
            }
        }
       
       
       
        printk(KERN_INFO "Timer with interrupt module inserted successfully
    ");
       
        return 0;
    }

    static void __exit timer_intr_exit(void)
    {
        unregister_chrdev(MAJOR_NUM,"gpio");t
        printk(KERN_INFO "Goodbye - timer_intr
    ");   
    }

    module_init(timer_intr_init);
    // subsys_initcall(timer_intr_init);
    module_exit(timer_intr_exit);

    MODULE_AUTHOR("David VandeBunte");
    MODULE_LICENSE("GPL");


    before loading this module cat /proc/interrupts is not showing any interrupt for 91. after loading this module the above command is showing interrupt on 91. but it is showing 0.

    output after loading my module:

    [ 3248.090000] timer_intr init
    [ 3248.090000] gpio: reg. size=65535 Bytes
    [ 3248.100000] gpio: virq=91
    [ 3248.100000] gpio: hw_irq=91
    [ 3248.100000] timer at 0x81200000 mapped to 0xE08A0000
    [ 3248.110000] Timer with interrupt module inserted successfully

    Please help me in this.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • zedhed
    0 zedhed over 12 years ago in reply to Former Member

    Hi anand4miitb,

    Can you please post the DTS entry related to your interrupt handler?

    I just wanted to repeat the recommendations from fletch and jkrachey.  The folks at Xillinux have some excellent tutorials, in particular this one may be useful to you:

    http://xillybus.com/tutorials/device-tree-zynq-4

    A little over half-way down on that page, they explain the following:

    "The second number is related to the interrupt number. To make a long story short, click the u201CGICu201D box in XPSu2019 main windowu2019s u201CZynqu201D tab, look up the number assigned to the interrupt (91 for xillybus in Xillinux) and subtract it by 32 (91 - 32 = 59)."

    Have you accounted for this interrupt offset in your DTS such that your device is registered under the appropriate interrupt?

    Regards,

    -Kevin

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube