view Calypso-test-reset @ 19:f68ca40fa5c1

Firmware-deblobbing document written
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 13 Sep 2019 07:28:00 +0000
parents 396d44c543e3
children
line wrap: on
line source

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!