• [海思] 中断申请和重启问题


    背景

    • 海思的硬件复位RSTN复位后无法启动,目前确定不了问题出在哪里

    • 另一方案:通过内核捕获gpio的中断后将整个系统复位,即软复位

    基本代码框架

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/cdev.h>
    #include <linux/uaccess.h>
    #include <linux/fs.h>
    #include <linux/io.h>
    #include <linux/ioport.h>
    #include <linux/device.h>
    #include <linux/miscdevice.h>
    #include <linux/gpio.h>
    #include <linux/interrupt.h>
    #include <asm/irq.h>
    #include <linux/sched.h>
    #include <linux/delay.h>
    #include <linux/reboot.h>
    
    struct st_gpio_int {
        int int_irq;//中断号
        int int_pin;//中断寄存器
        int int_num;//中断编号
        char *int_name;//中断名称
    };
    
    #define ARRY_SIZE(A) 			(sizeof(A)/sizeof(A[0]))
    #define GPIO_INT_READ			_IOR('L', 0x03, char [4])
    #define HI3531D_GPIO23_0		93
    #define REG_WRITE(addr, value)	((*(volatile unsigned int *)(addr)) = (value))
    #define REG_READ(Addr)			(*(volatile unsigned int *)(Addr))
    
    #define GPIO_23_BASE		    0x122C0000
    #define GPIO_23_DIR				IO_ADDRESS(GPIO_23_BASE + 0x400)//GPIO 方向控制寄存器
    #define GPIO_23_IS				IO_ADDRESS(GPIO_23_BASE + 0x404)//GPIO 中断触发寄存器
    #define GPIO_23_IEV				IO_ADDRESS(GPIO_23_BASE + 0x40C)//GPIO 触发中断条件寄存器
    #define GPIO_23_IC				IO_ADDRESS(GPIO_23_BASE + 0x41C)//GPIO 中断清除寄存器
    #define GPIO_23_IE				IO_ADDRESS(GPIO_23_BASE + 0x410)//GPIO 中断屏蔽寄存器
    #define GPIO_23_RIS				IO_ADDRESS(GPIO_23_BASE + 0x414)//GPIO 原始中断状态寄存器
    
    static const struct st_gpio_int gpio_reboot[] = {
            {HI3531D_GPIO23_0, 23, 0,"GPIO23_0_INT"},
    };
    
    static void hi3531d_pin_cfg(void)
    {
            unsigned char regvalue;
    
          //GPIO23_0
           /*配置作为普通输入 in=0 out=1 */
    	regvalue = REG_READ(GPIO_23_DIR);
    	regvalue &= ~(1<<0);
    	REG_WRITE(GPIO_23_DIR, regvalue);
    	
            /*GPIO4_7 管脚中断配置*/
    	regvalue = REG_READ(GPIO_23_IS);/*is=0 边沿触发中断 is=1 电平触发*/
    	regvalue |= (1<<0);
    	REG_WRITE(GPIO_23_IS, regvalue);
    
    	regvalue = REG_READ(GPIO_23_IEV);/*iev=1 上升沿触发,高电平触发中断 iev=0 下降沿触发,低电平触发中断*/
    	regvalue &= ~(1<<0);
    	REG_WRITE(GPIO_23_IEV, regvalue);
    
    	regvalue = REG_READ(GPIO_23_IC);/*ic清除中断*/
    	regvalue = 0xff;
    	REG_WRITE(GPIO_23_IC, regvalue);
    
    	regvalue = REG_READ(GPIO_23_IE);/*ie不屏蔽中断*/
    	regvalue |= (1<<0);
    	REG_WRITE(GPIO_23_IE, regvalue);
    }
    
    /*
     * Describe: gpio23_0 irq function 
     */
    static irqreturn_t gpio_reboot_eint(int irq, void *dev_id)
    {
            unsigned char regvalue;
    
            if( HI3531D_GPIO23_0 == irq)
            {
                regvalue = 0xff;
                REG_WRITE(GPIO_23_IC, regvalue);/*ic清除中断*/
    
                kernel_restart(NULL); //重启
            }
            return IRQ_HANDLED;
    }
    
    static int __init irq_init(void)
    {
            int ret = -1;
        	
            hi3531d_pin_cfg();
    
    
            ret = request_irq(gpio_reboot[0].int_irq, gpio_reboot_eint, IRQF_SHARED ,  //这里为共享中断
                              gpio_reboot[0].int_name, (void *)&gpio_reboot);
            if(ret)
            {
                printk("requtest EINT_%d(%s) failed:%d 
    ", gpio_reboot[0].int_irq, gpio_reboot[0].int_name, ret);
                goto err_gpio_request;
            }
        	
            printk("success
    ");
        	
            return 0;
    
    err_gpio_request:
    
    	return ret;
    }
    
    static void __exit irq_exit(void) 
    {
          free_irq(gpio_reboot[0].int_irq, (void *)&gpio_reboot);
    }
    
    module_init(irq_init);
    module_exit(irq_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_VERSION("v1.0");
    
    

    问题

    1. 中断申请标志位问题:

      • 申请中断时,使用request_irq,第三个参数为触发的方式,最初用的是IRQF_SHARED | IRQF_TRIGGER_HIGH 的标志位,出现以下问题:

        genirq: Setting trigger mode 8 for irq 93 failed (gic_set_type+0x0/0x90)
        
      • 猜想:应该是同组的其他GPIO也申请中断,并且申请的中断触发情况不同,在海思3531d中,GPIO20 - GPIO23共享一个中断号93

      • 解决方案:中断申请标志改为 IRQF_SHARED

      • 参考链接: https://www.pianshen.com/article/4986305785/

    2. 内核重启指令

      • 应用层直接使用system函数,而内核层没有相关函数,使用的是kernel_restart

        #include <linux/reboot.h>
        kernel_restart(NULL);
        
  • 相关阅读:
    Java SE入门(十三)——高级API
    Java SE入门(十二)——修饰符与内部类
    Java SE入门(十一)——接口与多态
    数据结构与算法(一)——绪论
    break与continue的区别以及终止函数的return false
    文字超出隐藏显示省略号及鼠标放上去显示全部文字信息的写法
    组件有新增修改两种状态该怎么使用
    Math常用的属性和方法
    模块化开发及import用法
    element时间日期选择器组件设置默认时间
  • 原文地址:https://www.cnblogs.com/chenj-nry/p/15226007.html
Copyright © 2020-2023  润新知