This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DM3730 FIQ handling

Other Parts Discussed in Thread: DM3730

Hi! I'm using DM3730 and 2.6.37 linux kernel based on TI BSP.

I need to handle FIQ triggered by GPIO105 pin. I've compiled my kernel driver with proper code, but got a silent system hang at the triggering moment. So I cannot understand, what I am doing wrong and what should I do.

driver code:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>

#include <asm/fiq.h>
#include <asm/io.h>

#include <plat/gpmc.h>
#include <plat/dma.h>

#define _FIQ_DEBUG_

#ifdef _FIQ_DEBUG_
#define _PDBA(_x_, args...)	printk("_PDB: "_x_, args)
#define _PDB(_x_)		printk("_PDB: "_x_)
#else
#define _PDBA(_x_, args...)	do {}
#define _PDB(_x_)		do {}
#endif

#define p347_FIQ_DRV_VERSION		"2013.12.13#001"

#define p347_GPIO_FPGA_IRQ		    105
#define p347_GPIO_BITPOS		    9
#define PADCONF_FPGA_IRQ_ADDR		0x2120
#define PADCONF_FPGA_IRQ_OFFSET		16
#define PADCONF_FPGA_IRQ_VALUE		0x011C

#define p347_GPIO_OSCIRQ		    57
#define PADCONF_OSCIRQ			    0x20B8
#define PADCONF_OSCIRQ_OFFSET		16
#define PADCONF_OSCIRQ_VALUE		0x0004

#define GPIO4_IRQSTATUS             0x49054018

static struct fiq_handler fh = {
    .name		= "p347_fpga_irq",
};

static int fh_id = 0;
static int i_cnt = 0;
static int irq_number = 0;

extern unsigned char p347_fiq_start;
extern unsigned char p347_fiq_end;

static int __init p347_fiq_init(void)
{
    int ret,i;
    u32 reg_val,old;
    size_t tmp_sz = 0;
    unsigned long rate;
    unsigned long scm_base = (unsigned long)ioremap(0x48000000,SZ_4K);
    unsigned long padconf_addr;
    unsigned long gpio_base = (unsigned long)ioremap(0x49054000,SZ_4K); //GPIO bank 4
    unsigned long mpuintc_base = (unsigned long)ioremap(0x48200000,SZ_4K);
    unsigned long tmp_addr;

    _PDBA("p347_fiq_init start, version = %s\n",p347_FIQ_DRV_VERSION);
    
    i_cnt = 0;
   
    //-----------------------------------------------------------fpga_irq pad configuration
    padconf_addr = scm_base + PADCONF_FPGA_IRQ_ADDR;
    reg_val = __raw_readl(padconf_addr);
    _PDBA("read irq padconf 0x%p ret 0x%x\n",(void*)padconf_addr,reg_val);
    if (PADCONF_FPGA_IRQ_OFFSET) reg_val &= 0x0000FFFF; else reg_val &= 0xFFFF0000;
    reg_val |= (PADCONF_FPGA_IRQ_VALUE << PADCONF_FPGA_IRQ_OFFSET);
    __raw_writel(reg_val,padconf_addr);
    reg_val = __raw_readl(padconf_addr);
    _PDBA("read irq padconf 0x%p ret 0x%x\n",(void*)padconf_addr,reg_val);

    irq_number = gpio_to_irq(p347_GPIO_FPGA_IRQ);
    _PDBA("gpio_to_irq ret irqnum=%d\n",irq_number);

    ret = gpio_request(p347_GPIO_FPGA_IRQ,"gpio_fpga_irq");
    if (ret != 0) {
	_PDBA("ERROR: cannot request gpio_fpga_irq, ret=%d\n",ret);
	return ret;
    }
    
    old = __raw_readl(gpio_base + 0x30); //GPIO_CTRL
    reg_val = 0; //enable module, no gating
    __raw_writel(reg_val,gpio_base + 0x30);
    reg_val = __raw_readl(gpio_base + 0x30);
    _PDBA("CTRL for GPIO old=0x%08x, new=0x%08x\n",old,reg_val);

    old = __raw_readl(gpio_base + 0x10); //GPIO_SYSCONFIG
    reg_val = 0x8; //No-idle mode
    __raw_writel(reg_val,gpio_base + 0x10);
    reg_val = __raw_readl(gpio_base + 0x10);
    _PDBA("SYSCONFIG for GPIO old=0x%08x, new=0x%08x\n",old,reg_val);
    
    __raw_writel(0,gpio_base + 0x20); //no wakeup enable
    
    old = __raw_readl(gpio_base + 0x34); //GPIO_OE
    reg_val = old | (1 << p347_GPIO_BITPOS); //set as input
    __raw_writel(reg_val,gpio_base + 0x34);
    reg_val = __raw_readl(gpio_base + 0x34);
    _PDBA("OE for GPIO old=0x%08x, new=0x%08x\n",old,reg_val);

    old = __raw_readl(gpio_base + 0x50); //GPIO_DEBOUNCEENABLE
    //reg_val = old & (~(1 << p347_GPIO_BITPOS)); //No debounce
    reg_val = old & (1 << p347_GPIO_BITPOS); //yes
    __raw_writel(reg_val,gpio_base + 0x50);
    reg_val = __raw_readl(gpio_base + 0x50);
    _PDBA("DEBOUNCEENABLE for GPIO old=0x%08x, new=0x%08x\n",old,reg_val);

    reg_val = __raw_readl(gpio_base + 0x4C); //GPIO4 FALLINGDETECT
    reg_val |= (1 << p347_GPIO_BITPOS);
    __raw_writel(reg_val,gpio_base + 0x4C);

    old = __raw_readl(gpio_base + 0x1C); //GPIO_IRQENABLE1
    reg_val = old | (1 << p347_GPIO_BITPOS);
    __raw_writel(reg_val,gpio_base + 0x1C);
    reg_val = __raw_readl(gpio_base + 0x1C);
    _PDBA("IRQENABLE1 for GPIO old=0x%08x, new=0x%08x\n",old,reg_val);

    ret = claim_fiq(&fh);
    if (ret) {
	_PDBA("Failed to claim FIQ, err = %d\n",ret);
    } else {
	    set_fiq_handler(&p347_fiq_start,&p347_fiq_start - &p347_fiq_end);

        //redirect to fiq
        tmp_addr = mpuintc_base + 0x100 + 4*INT_34XX_GPIO_BANK4;
        reg_val = __raw_readl(tmp_addr) | 0x1;
        __raw_writel(reg_val,tmp_addr);
        reg_val = __raw_readl(tmp_addr);
        _PDBA("IRQ %d redirected to FIQ, ILR reg=%08x\n",irq_number,reg_val);

        enable_fiq(irq_number);
    }

    ret = gpio_request(p347_GPIO_OSCIRQ,"gpio_oscirq");
    if (ret != 0) {
	    _PDBA("ERROR: cannot request gpio_oscirq, ret=%d\n",ret);
	    return ret;
    }
    padconf_addr = scm_base + PADCONF_OSCIRQ;
    reg_val = __raw_readl(padconf_addr);
    reg_val &= 0x0000FFFF;
    reg_val |= (PADCONF_OSCIRQ_VALUE << PADCONF_OSCIRQ_OFFSET);
    __raw_writel(reg_val,padconf_addr);
    
    gpio_direction_output(p347_GPIO_OSCIRQ,1);
    gpio_set_value(p347_GPIO_OSCIRQ,1);

    _PDB("p347_fiq_init end\n");
    return 0;
}
arch_initcall(p347_fiq_init);


static void __exit p347_fiq_exit(void)
{
    gpio_free(p347_GPIO_FPGA_IRQ);
}

module_exit(p347_fiq_exit);

Assembler code that should be executed on FIQ:

#include <linux/linkage.h>
#include <asm/assembler.h>

#define GPIO4_IRQSTATUS             0x49054018
#define GP57_SETREG                 0x49050094
#define GP57_CLRREG                 0x49050090
#define GP57_STATEREG               0x4905003C
#define GP57_BIT                    0x02000000

		.text

		.global	p347_fiq_end
		
ENTRY(p347_fiq_start)
	@clear bit in irq status, r8 - pointer, r9 - temporary value
        ldr r8,     =GPIO4_IRQSTATUS
	ldr r9,     [r8]
	orr r9,     #0x200
	str r9,     [r8]

        @load gpio data out, r8 - pointer, r9 - GPIO_DATAOUT, r10 - bit value
        ldr r8,     =GP57_STATEREG
        ldr r10,    =GP57_BIT        
        ldr r9,     [r8]        
        tst r9,     r10
        beq bit_clear

bit_set:
        ldr r8,     =GP57_SETREG
        str r10,    [r8]
        b bit_end
bit_clear:
        ldr r8,     =GP57_CLRREG
        str r10,    [r8]
bit_end:
		
	@restore
	subs	pc, lr, #4
p347_fiq_end:

In this asm code, each interrupt should toggle GPIO_57 pin.

  • Some addition:

    1) setting NEWFIQAGR has no effect

    ldr r8,     =INTCPS_CONTROL
    ldr r9,     =NEWFIQAGR
    str r9,     [r8]

    2) using virtual addresses instead of physical addresses for access from asm code has no effect:

    gpio_57 has not toggled, system is somewhere in silent hang

    3) Leaving only "subs pc, lr, #4" instruction has no effect

    So there is two possible reasons:

    A) My asm code is not called for FIQ handle. Something else is called... but what and why?

    B) My asm code is incorrect... so what should I do in this case?

  • Update: I have tested my ASM code as "standalone" code, and it works fine (I just have changed "beq bit_clear" to "bne bit_clear", and added push-pop).

    So I suppose that there is one reason of incorrect operation of FIQ handler: it had not registered properly, and CPU goes to undefined space. But why?