Legacy imx31/51 USB OTG under linux arcotg.ko spurrious interrupt

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Legacy imx31/51 USB OTG under linux arcotg.ko spurrious interrupt

Jump to solution
851 Views
andrewrobinson
Contributor I

During manual linux kernel driver initialization of the USB-otg gadget drivers typically used in SONY readers PRS900 and above, I am getting spurrious interrupts on irq 37.  It happens when the USB cable is not plugged in before the arcotg.ko driver loads for the first time for device/slave mode usb usage.

IT's reproduceable on a sonyPRS900 with the following code, reliably:  ( modules_09xx.tgz or modules_10xx.tgz)

http://www.sony.net/Products/Linux/Audio/PRS-900.html

The interrupt happens on IRQ 37 which is the interrupt normally associated with USB data transfer on the iMX31.

When the interrupt happens, none of the flags in the usb_dr_device (imx31 OTG hardware registers) indicate an interrupt has happened, and the host is stopped, etc.  eg: usbsts (USB Status Register) is clear.

Nor does pre-clearing the interrupts in the otgsc register solve the problem.

Although I have looked, I am having trouble finding hardware data sheets which describe interrupt sources for the USBOTG core in the iMX31, and how they are accessed/masked and routed to IRQ 37.  I believe, a PHY isp1504 may be present;

Where do I find information on how *ALL* the interrupts of the iMX31 are generated for USB-OTG, serviced, and masked at the hardware level so I can figure out how to mark the spurrious interrupt as serviced?

Failure to do so causes the interrupt to be disabled all together by the linux kernel after ~32 failed requests and the driver no longer works or detects cable plug ins or removals.

Labels (2)
0 Kudos
1 Solution
636 Views
andrewrobinson
Contributor I

I was able crudely solve it myself.

The data sheet  I needed was buried deeper in the site but I found it:  MCMIX31RM.pdf

The USB OTG linux kernel driver source code for 2.6.23, which has freescales' copyright info in it, doesn't initialize the USB_CONTROL register which is for nonstandard options that aren't part of the USB OTG specification, such as selecting iMX package pins and waking the processor from hibernation on an interrupt from an external PHY.    According to manual, the interrupt should only be enabled when entering hibernation mode, but when I checked the value it was enabled by default and the linux kernel driver never accessed it, likely because it's a nonstandard register.

I don't know why the PHY is issuing an interrupt in the first place... but there's really no need for wakeup on interrupt from the PHY when the processor is not in hibernation mode; so I simply added the following code to mask the interrupt enable for "wakeup", and the problem went away. eg: in modules_100930.tgz.  arcotg.c around line ~2719, right before interrupt 37 is enabled by:  tmp_status = request_irq(pdev->resource[1].start, arcotg_udc_irq,  IRQF_SHARED, driver_name, udc);

On the PRS900, I'm not sure why the PHY is issuing the interrupt in the first place since the cable was unplugged, so perhaps its' a hardware incompatibility or wiring issue.

I couldn't find the PHY chip, and the only chip on the motherboard which was unknown to me with a crystal resonator was an ST507B07 which I can't find a datasheet for; If anyone knows where I can get the datasheet, I'd appreciate it. :smileyhappy:

--Andrew.

// Code to disable wakeup interrupt from PHY...

{u32* usb_ctrl = (u32*)((char*)(void*)usb_slave_regs+0x600);
#define USB_CTRL_OWIR    (0x80000000) // OTG wake up interrupt request
#define USB_CTRL_OSICM    (0x60000000) // OTG serial interface configuration mask
#define USB_CTRL_OUIE    (0x10000000) // OTG ULPI wakes up interrupt enable
#define USB_CTRL_OWIE    (0x08000000) // OTG wake up interrupt enable
#define USB_CTRL_OBPM    (0x06000000) // OTG bypass mask,  RxDP and RxDM inputs
#define USB_CTRL_OPM    (0x01000000) // OTG power mask (disable dedicated pins)

#define USB_CTRL_H2WIR    (0x00800000) // H2's wake up interrupt request
#define USB_CTRL_H2SICM    (0x00600000) // H2's serial interface configuration mask
#define USB_CTRL_H2UIE    (0x00100000) // H2's ULPI wake up interrupt enable
#define USB_CTRL_H2WIE    (0x00080000) // H2's Wake up interrupt enable
//reserved                (0x00060000)
#define USB_CTRL_H2PM    (0x00010000) // H2's power mask (disable dedicated pins)

#define USB_CTRL_H1WIR    (0x00008000) // H1's wake up interrupt request
#define USB_CTRL_H1SIC    (0x00006000) // H1's serial interface configuration mask
//reserved                (0x00001000)
#define USB_CTRL_H1WIE  (0x00000800) // H1's wakeup interrupt enable
#define USB_CTRL_H1BPM  (0x00000600) // H1's bypass mask RxDP and RxDM inputs
#define USB_CTRL_H1PM    (0x00000800) // H1's power mask (disable dedicated pins)
//reserved                (0x000000C0)
#define USB_CTRL_H2DT    (0x00000020) // H2 disabled transciever mode (local usb)
#define USB_CTRL_H1DT    (0x00000010) // H1 disabled transciever mode (local usb)
//reserved                (0x0000000E)
#define USB_CTRL_BPE    (0x00000001) // bypass enable -- reroute H1 to OTG xcvr.

    printk(KERN_WARNING "udc: usb control %08x\n", *usb_ctrl );

    // Turn off all wake-up interrupt enables...
    // They should only be allowed when entering suspend mode!
    * usb_ctrl &= cpu_to_le32( ~(
                USB_CTRL_OUIE  | USB_CTRL_OWIE |
                USB_CTRL_H1WIE |
                USB_CTRL_H2UIE | USB_CTRL_H2WIE
    ) );
    printk(KERN_WARNING "udc: usb control %08x\n", *usb_ctrl );
}

View solution in original post

0 Kudos
1 Reply
637 Views
andrewrobinson
Contributor I

I was able crudely solve it myself.

The data sheet  I needed was buried deeper in the site but I found it:  MCMIX31RM.pdf

The USB OTG linux kernel driver source code for 2.6.23, which has freescales' copyright info in it, doesn't initialize the USB_CONTROL register which is for nonstandard options that aren't part of the USB OTG specification, such as selecting iMX package pins and waking the processor from hibernation on an interrupt from an external PHY.    According to manual, the interrupt should only be enabled when entering hibernation mode, but when I checked the value it was enabled by default and the linux kernel driver never accessed it, likely because it's a nonstandard register.

I don't know why the PHY is issuing an interrupt in the first place... but there's really no need for wakeup on interrupt from the PHY when the processor is not in hibernation mode; so I simply added the following code to mask the interrupt enable for "wakeup", and the problem went away. eg: in modules_100930.tgz.  arcotg.c around line ~2719, right before interrupt 37 is enabled by:  tmp_status = request_irq(pdev->resource[1].start, arcotg_udc_irq,  IRQF_SHARED, driver_name, udc);

On the PRS900, I'm not sure why the PHY is issuing the interrupt in the first place since the cable was unplugged, so perhaps its' a hardware incompatibility or wiring issue.

I couldn't find the PHY chip, and the only chip on the motherboard which was unknown to me with a crystal resonator was an ST507B07 which I can't find a datasheet for; If anyone knows where I can get the datasheet, I'd appreciate it. :smileyhappy:

--Andrew.

// Code to disable wakeup interrupt from PHY...

{u32* usb_ctrl = (u32*)((char*)(void*)usb_slave_regs+0x600);
#define USB_CTRL_OWIR    (0x80000000) // OTG wake up interrupt request
#define USB_CTRL_OSICM    (0x60000000) // OTG serial interface configuration mask
#define USB_CTRL_OUIE    (0x10000000) // OTG ULPI wakes up interrupt enable
#define USB_CTRL_OWIE    (0x08000000) // OTG wake up interrupt enable
#define USB_CTRL_OBPM    (0x06000000) // OTG bypass mask,  RxDP and RxDM inputs
#define USB_CTRL_OPM    (0x01000000) // OTG power mask (disable dedicated pins)

#define USB_CTRL_H2WIR    (0x00800000) // H2's wake up interrupt request
#define USB_CTRL_H2SICM    (0x00600000) // H2's serial interface configuration mask
#define USB_CTRL_H2UIE    (0x00100000) // H2's ULPI wake up interrupt enable
#define USB_CTRL_H2WIE    (0x00080000) // H2's Wake up interrupt enable
//reserved                (0x00060000)
#define USB_CTRL_H2PM    (0x00010000) // H2's power mask (disable dedicated pins)

#define USB_CTRL_H1WIR    (0x00008000) // H1's wake up interrupt request
#define USB_CTRL_H1SIC    (0x00006000) // H1's serial interface configuration mask
//reserved                (0x00001000)
#define USB_CTRL_H1WIE  (0x00000800) // H1's wakeup interrupt enable
#define USB_CTRL_H1BPM  (0x00000600) // H1's bypass mask RxDP and RxDM inputs
#define USB_CTRL_H1PM    (0x00000800) // H1's power mask (disable dedicated pins)
//reserved                (0x000000C0)
#define USB_CTRL_H2DT    (0x00000020) // H2 disabled transciever mode (local usb)
#define USB_CTRL_H1DT    (0x00000010) // H1 disabled transciever mode (local usb)
//reserved                (0x0000000E)
#define USB_CTRL_BPE    (0x00000001) // bypass enable -- reroute H1 to OTG xcvr.

    printk(KERN_WARNING "udc: usb control %08x\n", *usb_ctrl );

    // Turn off all wake-up interrupt enables...
    // They should only be allowed when entering suspend mode!
    * usb_ctrl &= cpu_to_le32( ~(
                USB_CTRL_OUIE  | USB_CTRL_OWIE |
                USB_CTRL_H1WIE |
                USB_CTRL_H2UIE | USB_CTRL_H2WIE
    ) );
    printk(KERN_WARNING "udc: usb control %08x\n", *usb_ctrl );
}

0 Kudos