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.

VUSB3V1 Non-Powerdown and Then USB OTG Doesn't Work

Other Parts Discussed in Thread: TPS65950, OMAP3530, SYSCONFIG

I have already posted this in the PMU forum (http://e2e.ti.com/support/power_management/pmu/f/43/t/84913.aspx), but was not able to get help there.

I have a working OMAP3530+TPS65950 system that uses the MUSB USB (OTG) port paired with the TPS65950's USB PHY in an embedded host-only mode:

  • ID signal tied to ground
  • VBUS tied only to a capacitor -- attached-embedded USB device separately powered (can switch on/off)
  • Nothing else connected to the PHY

I want to be able to have the MUSB (and hence all of CORE domain) go idle so I can reach lower power states.  I have it working fairly well.  I can power on and off the attached USB device and power up and down MUSB (and the TPS65950's PHY) as needed.  However, I learned (TPS TRM 15.4.11.3) that since we have a non-zero DC voltage on the ADCIN5 pin of the TPS65950 I risk chip damage if I don't keep VUSB3V1 powered on.

So I made a small change to keep VUSB3V1 powered on.  I set the VUSB3V1_REMAP register to 0xee, which I believe will keep it on always.  However, with that change the USB device isn't recognized anymore after I power down and power back up the MUSB and PHY.  The only difference between the working and non-working is the chagne to the VUSB3V1_REMAP register.

The sequence steps in the power transitions is shown below

Power down:

  1. Set OTG_FORCESTDBY to enable forced standby
  2. Set OTG_SYSCONFIG to force standby/force idle/wakeup-enable
  3. Save MUSB PHY context (i.e. registers)
  4. Turn off PHY power by setting PHYPWD bit in PHY_PWR_CTRL
  5. Disable VUSB regulators in this order: 1v5, 1v8, 3v1.
  6. Disable MUSB clocks

Power Up:

  1. Enable MUSB clocks
  2. Set OTG_FORCESTDBY to disable forced standby
  3. Set OTG_SYSCONFIG to no-standby/no-idle
  4. Enable VUSB regulators: 3v1, 1v8, 1v5
  5. Turn on PHY power by clearing PHYPWD bit in PHY_PWR_CTRL
  6. Set CLOCKGATING_EN & CLK32K_EN bits in PHY_CLK_CTRL
  7. Restore MUSB context (i.e. registers)

Comparing the working versus not-working cases (VUSB3V1_REMAP = 0x08 and 0xee respectively) with some debugging enabled I find that between steps 6 and 7 of the powerup steps that the MUSB DEVCTL register is read and in the working case it is 0x80, but in the non-working case it is 0x90.  This appears to be a VBUS valid error in the non-working case, as opposed to a Session End error in the working case.

In the working case I get another interrupt and it reads 0x5d from MUSB_DEVCTL, but no other interrupts are received in the non-working case.

I have tried enabling the VBUS charge pump before step 4 in the powerup sequence, but that didn't make any difference.

 

Any suggestions?


Thanks in advance,

 

Chris

 

 

  • With a little more instrumentation it looks like the working case has MUSB_DEVCTL reading a SessEnd interrupt from the PHY, but in the non working case (0xee written to VUSB3V1_REMAP to keep VUSB3V1 high) the SessEnd interrupt is missing, and only the VbusValid bit  is set in the PHY.

    Since the working case gets another interrupt and that interrupt starts enumerating the embedded device, and the non-working case doesn't get another interrupt, do you know if getting a SessEnd interrupt causes some kind of retry that only having VbusValid doesn't?

     

    Thanks,

     

    - Chris

  • Hi Chris,

    I will have to find details about SessEnd interrupts.

    Can you try to see if the behavior changes if you have the VUSB3V1_REMAP set to 0x88?

    This will keep the LDO in sleep state (low power) instead of active. Not looking at the interrupts it seems that the problem is due to the 3.1V LDO being continuously in the active state. I am not sure if you will see any difference. However, this will provide more information.

    You dont have to enable the CP when you have an external VBUS supply.

    I will get back to you with more information.

     

    Regards,

    Gandhar.

     

     

  • > Can you try to see if the behavior changes if you have the VUSB3V1_REMAP set to 0x88?

    Thanks for the idea, Gandhar.  I had tried that and it didn't make any difference.

    > I will get back to you with more information.

    Thanks very much,

    Chris

  • Hi Chris,

    Here is something that I discussed with another colleague. Sorry for not providing a confirmed answer so far. I have some update from Tiemen and will be able to address that tomorrow.

    Here is what we think may be happening. Since you have to keep the 3.1V LDO ON, the PHY may be in some undefined state when you go to idle mode. So, when returning to active state it may be helpful to reset the PHY prior to doing any handshake with the LINK.

    Can you try reseting the PHY by setting bit FUNC_CTRL[5]? You can also try powering down the entire PHY using bit PHY_PWR_CTRL[0], before you start handshake. 

    Please let me know if this helps.

     

    Regards,

    Gandhar.

     

  • Have you tried to toggle the USB transceiver reset (bit 5 of the FUNC_CTRL register)?  You may want to set this bit high in the same place you were turning on the power and setting resolves the problem.  Turning the transciever power off/on may be initalizing something that gets into a bad state when you leave the power on and suspend the USB contoller.

     

    Regards,

    Paul

  • Thanks for the suggestions, Gandhar.

    The driver code already powers down the PHY using PHY_PWR_CTRL[0].  I have tried resetting the PHY with FUNC_CTRL[5], but it didn't solve the problem.

    Your suggestions did point me in a direction that seems to be helping, however.  I looked at the sequence of events with the powering up of the MUSB and PHY.  In that sequence the MUSB was getting an interrupt from the PHY as soon as the PHY's clock was enabled--before I could even reset the PHY.  It turns out that the MUSB has a wakeup feature (that was enabled) that turned it on as soon as the PHY was powered up.  By disabling the wakeup feature, the MUSB block stays idle/standby until after the PHY is configured and the MUSB registers are restored.

    Thanks for the help,

    Chris

  • Hi Chris,

    Does that mean that you do not see any problem?

    Changing the MUSB setting you can see proper idle-to-wakeup transitions?

     

    Regards,

    Gandhar.

     

  • Hi Gandhar,

    The PHY now seem to be working--thought I'm still testing.  I'm having a different issue on the MUSB side now.

    After coming out of MUSB off mode, the MUSB registers aren't accessible.

    Thanks for your help and suggestions.

    Chris

     


     

     

    P.S.  After further testing, the problem of getting incorrect interrupts seems to be solved by disabling the MUSB wakeup.  Now there seems to be a problem with accessing MUSB control registers after waking up from OFF mode.

     

    P.P.S.  The rest of the postings in this thread are actually unrelated to this issue.  They were the next step in achieving OFF mode, but I didn't initially realize that they weren't related to keeping VUSB3V1 from turning off.  The thread pertaining to the below postings can be found here: http://e2e.ti.com/support/dsp/omap_applications_processors/f/447/p/89881/311504.aspx#311504

  • Please specify which MUSB register bits you changed which cause the MUSB registers not to be accessible.

     

    I will ask the software driver team to review your forum post and determine if the register bits you changed have a compatibility issue with the driver.

     

    Regards,

    Paul

  • Thanks, Paul.

    I actually didn't change any accesses to the MUSB registers--at least not in the NDA requiring MUSB core itself.  I am changing registers that control idle, power, clock, etc.:  My function that sets MUSB to idle and wakes it back up again is:

    int musb_myidle(struct musb *musb, int go_idle)
    {
            static int am_idle = 0;
            if (go_idle) {  // Request that MUSB go idle : !active
                    if (am_idle) {
                            INFO("Requested MUSB go idle, but it\'s already idle\n");
                            return -EINVAL;
                    } else {        // Tell it to suspend
                            INFO("Setting MUSB to idle\n");
                            musb_link_force_active(0);
                            otg_set_suspend(musb->xceiv, 1);
                            // Disable clock?
                            if (musb->set_clock) musb->set_clock(musb->clock, 0);
                                            else clk_disable(musb->clock);
                            am_idle = 1;
                            return 0;
                    }
            } else {        // Request that MUSB go active : !idle
                    if (am_idle) {  // Tell it to go active
                            INFO("Setting MUSB to active\n");
                            // Enable clock?
                            if (musb->set_clock) musb->set_clock(musb->clock, 1);
                                            else clk_enable(musb->clock);
                            msleep(1);
                            musb_link_force_active(0); // Make sure inactive so nothing happens until ready...
                            otg_set_suspend(musb->xceiv, 0);
                            musb_link_force_active(1); // Swapped with line before
                            am_idle = 0;
                            return 0;
                    } else {
                            INFO("Requested MUSB go active, but it\'s already active\n");
                            return -EINVAL;
                    }
            }
    }

    This was added to the Android kernel's driver hosted at

    http://git.omapzoom.org/?p=kernel/omap.git;a=shortlog;h=refs/heads/p-android-omap-2.6.32

    The highlighted line is where the exception occurs, which is accessing the OTG_FORCESTDBY and OTG_SYSCONFIG registers.  If CORE is in retention mode the above code doesn't have any trouble.  If CORE has been in OFF mode, then the exception occurs.

    Thanks,

     

    Chris

     

  • The above function is called both to enable and disable the MUSB and PHY.  It seems to work pretty well when power management's OFF mode isn't enabled.  It has trouble as soon as power management's OFF mode has been achieved by the CORE powerdomain.

    I tested the value of CM_IDLEST1_CORE just before the call to the highlighed  musb_link_force_active(0) in the above code.  When OFF mode hasn't been acheived by the CORE powerdomain, CM_IDLEST1_CORE is 0xffff9f8d, and the code works.  After OFF mode has been achieved by the CORE powerdomain the value for CM_IDLEST1_CORE is 0xffff9f9d. and the exception occurs.

    The difference is bit 4, which Rev. M of the TRM indicates the OTG's (MUSB's) standby status, which seems to be standby mode.  I'm a little surprised that this bit isn't always set at this point in the code, since I've set it to force idle.

    Rev. M of the TRM indicates that if CM_IDLEST1_CORE bit 5 is zero, (which it is in both cases), then HS OTG USB can be accessed, however, the above code gets an exception...

    Am I misinterpreting the TRM?

    Is there something else that I'm not considering?

    Thanks,

    Chris

  • With a little more sleuthing, it looks like the crash occurs after the MUSB registers have been restored, but it's the read of OTG_SYSCONFIG that causes the fault:

    Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa0ab404
    Internal error: : 1028 [#1]
    last sysfs file: /sys/devices/platform/musb_hdrc/mode
    Modules linked in: sierra_net usbnet mii sierra omap2_mcspi [last unloaded: omap_hsmmc]
    CPU: 0    Not tainted  (2.6.32 #184)
    PC is at omap_readl+0x4/0xc
    LR is at musb_link_force_active+0x10/0xcc
    pc : [<c004cdd8>]    lr : [<c021042c>]    psr: 60000013
    sp : c5617ee8  ip : 0000054a  fp : 000acb34
    r10: 40021000  r9 : 00000000  r8 : 00000000
    r7 : 00000003  r6 : a0000013  r5 : 00000001  r4 : c5c638e8
    r3 : c01f76dc  r2 : 0000000f  r1 : fa0ab000  r0 : fa0ab404
    Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
    Control: 10c5387d  Table: 85424019  DAC: 00000015
    Process musbloop-off (pid: 1498, stack limit = 0xc56162e8)
    Stack: (0xc5617ee8 to 0xc5618000)
    7ee0:                   c5c638e8 c5c638e8 a0000013 c02105f8 00000000 c5511000
    7f00: c5c638e8 c020f480 c5c65ab8 c54feb40 00000003 c045a190 c0477460 c01bc870
    7f20: 00000003 c00f50c8 c5fe9740 c54feb40 c54feb58 c5617f80 00000003 c00f5410
    7f40: c5617f80 00000003 c5fe9740 40021000 c5617f80 00000000 00000000 c00b01f8
    7f60: c5fe9740 40021000 c5fe9740 40021000 00000003 00000004 00000000 c00b0340
    7f80: 00000000 00000000 00000003 00000000 00000003 4020e5c8 00000003 c002ffe8
    7fa0: c5616000 c002fe40 00000003 4020e5c8 00000001 40021000 00000003 00000000
    7fc0: 00000003 4020e5c8 00000003 00000004 40021000 000ad3f0 00000001 000acb34
    7fe0: 00000000 bed4bef8 40134e98 40191adc 60000010 00000001 00000000 00000000
    [<c004cdd8>] (omap_readl+0x4/0xc) from [<c021042c>] (musb_link_force_active+0x10/0xcc)
    [<c021042c>] (musb_link_force_active+0x10/0xcc) from [<c02105f8>] (musb_myidle+0x110/0x154)
    [<c02105f8>] (musb_myidle+0x110/0x154) from [<c020f480>] (musb_mode_store+0xb8/0xdc)
    [<c020f480>] (musb_mode_store+0xb8/0xdc) from [<c01bc870>] (dev_attr_store+0x1c/0x20)
    [<c01bc870>] (dev_attr_store+0x1c/0x20) from [<c00f50c8>] (flush_write_buffer+0x48/0x5c)
    [<c00f50c8>] (flush_write_buffer+0x48/0x5c) from [<c00f5410>] (sysfs_write_file+0x4c/0x74)
    [<c00f5410>] (sysfs_write_file+0x4c/0x74) from [<c00b01f8>] (vfs_write+0xb0/0x148)
    [<c00b01f8>] (vfs_write+0xb0/0x148) from [<c00b0340>] (sys_write+0x3c/0x68)
    [<c00b0340>] (sys_write+0x3c/0x68) from [<c002fe40>] (ret_fast_syscall+0x0/0x2c)
    Code: e28004b2 e1d000b0 e12fff1e e28004b2 (e5900000)

    Why would it be able to access the MUSB registers, but not the MUSB control register OTG_SYSCONFIG?  I'm confused.

    - Chris

  • Chris,

    Are both CORE_L3_ICLK and CORE_L4_ICLK enabled when OTG_SYSCONFIG was accessed ? What are the settings for PRCM.CM_ICLKEN1_CORE[4] and PRCM.CM_AUTOIDLE1_CORE[4] just before accessing OTG_SYSCONFIG ?

  • Kazunobu,

    CM_AUTOIDLE1_CORE = 0xfffffed9 -- so bit 4 = 1
    CM_ICLKEN1_CORE = 0x00006052   -- so bit 4 = 1

    - Chris

  • Kazunobu,

    Also:

    CM_CLKSTST_CORE = 0x00000003
    CM_CLKSTCTRL_CORE = 0x0000003f
    CM_CLKSEL_CORE = 0x0000030a

    This seems to indicate that L3 and L4 clocks are both active, correct?

    Thanks,

    Chris

  • Chris,

    Yes, it looks L3_ICLK and L4_ICLK are both active. However there are other switches before being feeded to HS USB OTG as shown in "Figure 4-45. CORE Clock Signals: Part 1" in the TRM. I'd like to make sure both switches are enabled. Could you also check the CM_AUTOIDLE3_CORE[2] AUTO_USBTLL status, change it to 0 if it's 1 and try to read OTG_SYSCONFIG again ? If it doesn't work, can you check if you can access the other registers listed in Table 23-8 in the TRM (spruf98m.pdf) ? 

     

     

  • Originally CM_AUTOIDLE3_CORE was 0x0000000c at the point of crashing.  I wrote 0, instead so that it read 0x00000000.

    It still crashed when reading OTG_SYSCONFIG after achieving CORE OFF mode.

    as you suggested, I tried reading the registers in Table 23-8 at the same point in the code where it crashed when reading OTG_SYSCONFIG, with the following results:

    Register Name Value Read Normally Crashed?
    OTG_REVISION 0x00000033 Crashed
    OTG_SYSCONFIG 0x00000000 Crashed
    OTG_SYSSTATUS 0x00000001 Crashed
    OTG_INTERFSEL 0x00000001 Crashed
    OTG_SIMENABLE 0x00000000 Crashed
    OTG_FORCESTDBY 0x00000001 Crashed

    By the way, according to the TRM, CM_AUTOIDLE3_CORE[3] is reserved and should read as 0, but didn't.  Is that something I should be concerned about?  Should I have written 0x00000008 instead of 0 to CM_AUTOIDLE3_CORE?

    Thanks again for your assistance,

    Chris

  • I am having the same issue where bit 4 of CM_IDLEST1_CORE is set.  I can't seem to clear this condition.

    I have read this thread, but I do not know how you either prevented this condition or cleared this condition.

    Can you please elaborate how this issue was fixed.

    thank you

    Ray