Reset logic and on/off states in the Calypso+Iota chipset ========================================================= Our beloved Calypso+Iota chipset provides a special reset signal (called nTESTRESET on Leonardo schematics) that is just for testing, development and debugging, not used at all in the normal life cycle of a phone handset or modem. This special test reset is triggered when you press the RESET button on a TI/FreeCalypso development board (D-Sample or FCDEV3B), and it can also be triggered slightly indirectly through the reset pin on the TI-style JTAG connector. The way this reset works is very quirky and requires a lot of explanation, but before one can properly understand this test reset, we first need to look at the "regular" power-on reset, switch-on and switch-off logic that works in the absence of nTESTRESET. Before looking at resets and switch-on and switch-off sequences, we first need to understand the power domains that are involved. There are two major power domains of interest: there is the main power domain that is physically powered off when the mobile device is not in the switched-on state, and there is the RTC power domain that is powered at all times whenever the battery is physically present, or perhaps even from a separate backup battery (a tiny coin cell) that provides RTC power when the main battery is removed. The always-on RTC power domain allows the real time clock to maintain the time of day while the mobile is otherwise off (hence the name), and it also provides power to the logic that allows the rest of the mobile (the main power domain) to be powered on, initialized, booted, run and eventually switched off again in an orderly manner. All reset and on/off logic in our chipset happens in the VRPC (Voltage Reference and Power Control) block in the Iota chip; all of Calypso and the rest of Iota are fully subservient to this VRPC block. It is crucial to understand the difference between powering on and off vs. switching on and off: in the terminology that is established in TI's chip datasheets and application notes, powering on means physically providing battery power to the chipset (inserting the battery into a phone that had it removed, or connecting a VBAT power supply to the orange power input connector on one of our development boards), and powering off means physically removing all battery power, i.e., yanking the battery out of a phone or disconnecting the power supply from the development board. In board designs with a backup battery or a provision for one, it is even more complicated: a power-on happens when either the main battery or a backup battery becomes present, and a power-off happens when both batteries are removed, leaving the Iota chipset without any energy source whatsoever. In contrast, the actions of a user turning her phone on and off are called switch-on and switch-off, respectively. The RTC power domain is powered on and receives its power-on reset (POR) on a power-on event and loses power only on a full power-off (complete loss of all battery power), whereas the main power domain is powered on and lifted out of reset only on a switch-on, and powered back down and held in reset on a switch-off. The Calypso chip receives two reset signals from the Iota (meaning that each signal is an output from the Iota and an input to the Calypso): nRESPWON and ON_nOFF. The nRESPWON signal is asserted (active low) only on a hardware power-on (and also on nTESTRESET as will be explained in due course) and stays high (inactive) at all other times, whereas ON_nOFF is driven high on switch-on and low on switch-off. When the ON_nOFF signal is driven low by the Iota ABB in the switched-off state, all main (non-RTC) logic in the Calypso is held in reset, and in any case that logic cannot function as the physical power to it (coming from LDO regulators in the Iota) will typically be turned off. When the Iota ABB drives ON_nOFF high on switch-on, it does so after the LDO regulators for the main power domain have been turned on and have had enough time to stabilize; in the Calypso chip the transition of ON_nOFF from low to high causes the ARM7 core to boot. A true power-on reset happens only when all battery power is removed and reconnected: in simple designs without a backup battery one would need to remove the main battery or the power supply providing VBAT and also disconnect anything that may be feeding power into the system through pull-up resistors; in more complex designs that feature a backup battery, both the main battery and the backup battery would need to be removed and reconnected in order to trigger a POR. Such a complete POR would reset the RTC power domain, and on exit from the POR the VRPC block will be in the switched-off state, with everything except the RTC powered off and waiting for the user to press the PWON button. The green LED on the FCDEV3B indicates the state of the ON_nOFF signal, and thus allows you to see if the VRPC block is switched on (LED on) or switched off (LED off). The actual VRPC state machine in the Iota chip is a little more complicated and has 5 states, not just two (the states are NOBAT, BACKUP, OFF, ACTIVE and SLEEP), but I am simplifying here - for the complete details, please see the VRPC description in Iota datasheet TWL3025_SWRS021.pdf, section 4.10 starting on page 40. The transition from OFF to ACTIVE (switch-on event) happens whenever the PWON button is pressed or charging voltage is applied (on hardware that has charging circuits), whereas commanding a switch-off (going back to OFF) requires having Calypso ARM7 firmware establish communication with the Iota ABB over SPI and send a DEVOFF command. If the Calypso firmware requests a switch-off when the PWON button is held down (jumper on FCDEV3B) or when a charging power source is present, the Iota VRPC goes through a switch-off immediately followed by a switch-on, effecting a very deep kind of reboot. nTESTRESET enters the picture ============================= So where does nTESTRESET fit in the just-described architecture of on/off switching and resets? Contrary to what one might naively think, it is NOT an externally-triggerable way to simulate a POR, nor is it simply ANDed or ORed together with some other internal reset signal. Instead as you can see in Figure 4-8 on page 43 of the TWL3025_SWRS021.pdf datasheet, it is its own separate and very special path through the VRPC state machine that is never exercised at all in normal product operation. When you press the RESET button or trigger a reset through JTAG connector pin 2 (let's call it XDS_RESET), the VRPC state machine will unconditionally leave whatever state it was in and will be forced into this special nTESTRESET state that does not occur at any other time. For as long as nTESTRESET is held low, both reset signals to the Calypso (nRESPWON and ON_nOFF) will be held low as well, putting the Calypso into a POR-like superdeep reset, but meanwhile the LDO regulators are fully turned on, not off! While nTESTRESET is held low, the green LED on the FCDEV3B will be off (ON_nOFF is low), but the regulators are on, as can be seen on JTAG connector pin 5 where the V-IO rail is brought out. This combination of ON_nOFF low (green LED off) but regulators on happens only in this special nTESTRESET-held-low state and not at any other time. When the RESET button and XDS_RESET are both released, causing nTESTRESET to go back to high, the VRPC state machine goes from the special nTESTRESET state to the ACTIVE (switched-on) state via a special direct transition that bypasses the normal checks. Calypso reset inputs nRESPWON and ON_nOFF go from low to high at the same time (this is the only time when they do it like this), and the ARM7 core boots. Thus the test reset triggered via nTESTRESET is not a simple POR-like reset, instead it is a very special "deep reset, then unconditional power-on and boot" kind of operation. As a practical matter, it does its intended job of giving developers an unconditional and unstoppable way to take control of the chipset when the ARM7 processor and its code execution are in a runaway state: in the Calypso+Iota on/off architecture, the most "kosher" way to cleanly reset the system would be a switch-off followed by a switch-on, but a normal switch-off is a quite complex operation that has to be performed by ARM7 firmware, and it is thus unavailable when the processor executes something other than perfectly good firmware code with clean soft-power-off functionality. The test reset mechanism provides a solution, although it is a solution that may be quite difficult to understand at first. It is also important to note that nTESTRESET acts the same way and puts the chipset into the exact same state regardless of *all* prior state, as in not only prior sw state, but also prior hw state: in particular, it works exactly the same way whether the chipset was switched on or switched off prior to nTESTRESET assertion. If the system was previously switched on, running some code that hung or become uncontrollable, nTESTRESET can be thought of as acting mostly like a typical processor reset that most software developers are used to, but if the system was previously switched off, nTESTRESET acts like a different kind of "turn on" command, producing a switch-on that is distinguishable from all other switch-on causes like PWON and charger-plug. Lack of debouncing ================== It is important to note that there is no debouncing circuit for nTESTRESET inside the Iota chip, like there is for the regular PWON button. Thus shorting nTESTRESET to GND directly with a finger-actuated pushbutton switch is not particularly good, although TI's Leonardo schematics depict just such an arrangement, and it works OK on the FCDEV3B in practice. The entity that drives nTESTRESET to the Calypso+Iota system takes full responsibility for ensuring proper timing. The reset which is propagated from nTESTRESET to nRESPWON and ON_nOFF needs to have a certain duration in order to reset all logic properly, and there is nothing in the chipset itself to assure such, unlike what happens on normal switch-on sequences - instead it is the responsibility of the nTESTRESET driving source. The exact timing requirements are not stated anywhere (at least none that we could find), but if you are driving nTESTRESET from a programmatic source (presumably via the XDS_RESET signal path described below), I would give it a 50 ms pulse. When nTESTRESET is shorted to GND with a finger-actuated pushbutton switch, one needs to watch out for contact bounce. If the dry contact switch does a lot of make-break bounce, that make-break noise will translate directly into Calypso and Iota resets being asserted and negated just as rapidly, which is certainly not clean. The final release from reset is the most important part though: if the system is put through a bunch of erratic resets as a result of contact bounce on the initial RESET button press, there should be no problem if there is a long solid reset at the end, with a clean release from it. But if the release from reset is also accompanied by contact bounce with make-break events on the order of microseconds, then the chipset may enter garbage state by way of an improperly timed reset. The nTESTRESET signal was clearly designed to be driven by development systems that can produce controlled timing, not by bounce-prone electromechanical switches driven by bounce-prone human fingers. nTESTRESET vs. XDS_RESET ======================== In its native form the internal nTESTRESET signal is pulled up to a non-logic voltage rail (specifically UPR, which normally follows VBAT in the absence of backup batteries), and it can be shorted or pulled to GND either by pushbutton switches (aside from the contact bounce problem noted above) or by OC/OD drivers. It cannot, however, be driven by any kind of external push-pull driver, and more generally it cannot be connected to any circuit that operates on standard logic voltages like 3.3 V - the VBAT rail will typically be in the 3.6 to 4.2 V range, which is too high for external 3.3 V logic. But TI Back In The Day had a need to drive this test reset from their XDS510 and XDS560 "emulator" pods, and the only reset signal those pods put out is the one that was originally intended for JTAG TRST (which does not exist in the Calypso+Iota chipset), driven with a push-pull driver. TI's solution was to insert a clever transistor circuit between JTAG connector pin 2 (the pin that was originally intended to be TRST) and the internal nTESTRESET signal; this circuit is depicted on the available Leonardo schematics, it has been replicated on our FCDEV3B, and we have every reason to believe that it is the same on TI's D-Sample board as well. The effect of this circuit is that whenever the external XDS_RESET signal is driven low and the internal V-IO rail has power (see below), the internal nTESTRESET signal is driven low (asserted), and whenever the external XDS_RESET signal is either driven high or left alone, the internal nTESTRESET signal is left alone, high from the pull-up to UPR - but the nTESTRESET and XDS_RESET electrical nets are never exposed directly to each other's voltages. This clever solution does however have one side effect which is visible to developers working with these boards: the reset signal isolation circuit can only propagate an asserted low from XDS_RESET to nTESTRESET when the V-IO rail has power, i.e., when Iota regulators are turned on - and in the normal switched-off state these regulators are turned off. Thus the operator needs to first cause a switch-on or at least a regulator turn-on by pressing either the PWON button or the RESET button, and once V-IO is on, the external host driving the XDS_RESET signal via the JTAG connector can take over. Another unexpected quirk is that XDS_RESET can still sometimes work even though the Iota regulators are off (VRPC in the switched-off state) if some leakage power is being fed into the V-IO rail from UART or JTAG lines through pull-up resistors - but this behaviour should be considered an unfortunate design blemish, not something to be relied on. Test reset, then switch-off, then switch-on quirk ================================================= If you use any version of FreeCalypso host tools earlier than the upcoming fc-host-tools-r11 release with an FCDEV3B, you might have noticed a really odd quirk: if you make an fc-loadtool entry via the RESET button instead of PWON, then exit your loadtool session cleanly, such that the green LED goes out, the board ends up in a weird state - if you then do a subsequent switch-on via PWON, something goes wrong (fc-loadtool entry doesn't work, regular fw also hangs instead of producing rvinterf output) - it seems as though if you have done a RESET once, only another RESET works from then on, and PWON stops working correctly. Yet if you press the RESET button without fc-loadtool and let the regular firmware boot from this nTESTRESET switch-on, and then execute a switch-off through the firmware (AT@POFF, fc-shell poweroff, or press, hold and release the PWON button) the board is powered off in a clean state - subsequent PWON works just fine. What in the world is going on? The secret magic was discovered by carefully studying the TCS211 firmware code we've inherited from TI. It turns out that our Iota chip has at least one secret undocumented register (or perhaps many more, who knows) that is not documented in the TWL3025_SWRS021.pdf datasheet, and any Calypso programs (full firmwares or standalone programs like our loadagent) that execute a Iota poweroff (really switch-off) operation need to make a special write to this magic register in order to avoid trouble in the test reset, then switch-off, then switch-on sequence. We are calling this undocumented Iota register VRPCAUX (its official name is unknown, but there is a seemingly-corresponding register in TI's newer Syren ABB chip which the firmware calls VRPCAUX, and the name logically fits in terms of the function), and it is accessed via undocumented register page 2. Officially both Iota and Syren ABB chips only have register pages 0 and 1, but it turns out that both chips also have an undocumented page 2 - and in order to access this secret page 2, one first needs to issue a special (also secret) unlock command through yet other registers - whew! So just *why* do we need to mess around with secret undocumented Iota registers from our production code? From what we can tell, this VRPCAUX register lives in the VRPC block in the RTC power domain, and it preserves its state when the rest of the system is powered down in the switched-off state. Apparently this register controls some aspects of the switch-on process, and when an nTESTRESET reset-and-boot sequence is performed, this VRPCAUX register is loaded with a different configuration than on normal POR. It appears that the "normal" value of VRPCAUX in the absence of test reset operations is 0x007 (bit meaning unknown of course when we are dealing with secret undocumented stuff), and this value is needed for switch-on and possibly other things (sleep entry and exit, ABB interrupts, who knows) to work correctly. But if we boot via nTESTRESET and read the secret register, we see 0x2E7 instead - and if we do a normal DEVOFF command without changing it to 0x007 first, we get into the broken state where PWON switch-ons don't work. (It is very reassuring though that another nTESTRESET always works no matter what - so it looks like this debug reset is truly irrespective of all prior hw state.) TI's TCS211 firmware has a bit of magic in its boot code path in the ABB_on() function in the chipsetsw/drivers/drv_core/abb/abb.c module, and it has this attention-drawing comment: // Restore the ABB checks and debouncing if start on TESTRESETZ The code following this comment goes through the gymnastics of enabling access to register page 2, then writing 0x007 into the register which we've named VRPCAUX. (That's what it does for Iota; for Syren it also writes a few other registers also in that same undocumented page 2.) Reproducing these steps in our target-utils code (loadagent and friends) has resulted in the problem behaviour going away: now we can enter fc-loadtool via the RESET button, then exit loadtool (loadagent poweroff command executed on the target), and the board is powered off cleanly, with both PWON and RESET working for subsequent switch-ons. Whew!