view Calypso-JTAG-notes @ 96:69061d044f05

Voice-memo-feature: new article
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 27 Dec 2022 20:23:55 +0000
parents 7ba5c951803c
children
line wrap: on
line source

This document describes the quirks of Calypso JTAG in an abstract, tool-
independent sense, and also covers the little bit of experience we've had with
TI's original official tools, but does not delve into OpenOCD specifics.
For OpenOCD-on-Calypso custom config and instructions, please refer to the
freecalyps-hwlab repository - but the present document should still be read
first.

Unconventional reset structure
==============================

The first major way in which the JTAG interface on Calypso development boards
(or more generally, what is available in the Calypso+Iota chipset) differs from
"canonical" JTAG is that this chipset does NOT have reset signals that are
anything like classic TRST or SRST.  Instead there is only one bundled-with-JTAG
reset signal (we call it XDS_RESET) which is turned into Iota nTESTRESET through
a transistor circuit - please refer to the Calypso-test-reset article.  Aside
from its effects on the VRPC state machine described in that article, this test
reset can be thought of as a simultaneous combination of an equivalent of TRST
(all JTAG logic is hard-reset), an equivalent of SRST (the Calypso is fully
reset and proceeds with a cold boot) and more (all hardware is reset at a very
deep level), but comparisons to classic TRST and SRST aren't really appropriate
as the latter signals simply don't exist in our chipset.

However, despite its highly unconventional nature, this XDS_RESET signal
provided along with JTAG on TI's development boards performs a very important
function: this combination of JTAG and test reset allows a "reset and hold
still" maneuvre where all hardware is put into its pristine state with a very
deep reset, but the ARM7 CPU is halted before it gets a chance to execute any
instructions from the reset vector.  This ability is not particularly important
on current Calypso hardware with a working and enabled boot ROM, but it was
vital on earlier platforms without this boot ROM: if the flash is blank or
contains a bad code image, or if RAM is mapped onto the boot chip select
instead of flash, allowing the ARM7 core to execute garbage out of reset is
bad, whereas having a "reset and hold still" ability allows guaranteed reliable
recovery and bootstrapping from a blank or bricked state.  As explained later
in this article, this "reset and hold still" maneuvre is executed by first
giving the target a test reset pulse (which unstoppably blows away all prior hw
state), then immediately (the timing is critical) performing certain
manipulations via the JTAG scan chain - thus the bundling of the XDS_RESET
signal with JTAG is important.

EMU0 and EMU1 signals
=====================

In addition to the 4 standard JTAG signals TCK, TDI, TDO and TMS, the Calypso
provides two TI-proprietary signals called EMU0 and EMU1.  (The test reset goes
to the Iota ABB, not to the Calypso.)  These EMU0 and EMU1 signals are brought
out to the 14-pin JTAG connector on TI's D-Sample and E-Sample boards, and also
on our FCDEV3B.

The function of these two signals is completely unknown: all we know is that
they are listed as "bidirectional in/out" in the cal000.pdf document, and that
same-named signals also exist on TI's general-purpose DSP chips, both C54x and
the newer families, where they are also very poorly documented.  We don't know
what these EMU0/1 signals do on the Calypso, and it is a particular unknown
whether they are specific to the DSP part or if the ARM7 part can also make use
of them somehow.

I (Mother Mychaela) previously thought that these signals might facilitate a
way to halt the ARM7 core without going through the scan chain, or a different
way to halt directly out of reset than the one we ultimately found, but a
recent experiment has shown that pulling either or both of these signals low
(they are pulled up on target boards) has absolutely no visible effect on ARM7
code execution, whether they are pulled low coming out of test reset or while
running.  Thus until we recover more understanding of what is going on inside
the chip, we are going to ignore these two signals and leave them unconnected.

Iota not included in the JTAG scan chain
========================================

In addition to the Calypso chip itself (the DBB), the Iota ABB chip also has
JTAG pins and could potentially be included in the scan chain.  However, this
wiring arrangement is not typically used: both on TI's D-Sample board and on
our own FCDEV3B (based on Leonardo schematics) the JTAG interface is wired only
to the Calypso and not to Iota.  The same arrangement has also been found in
all historical commercial phones and modems that provide a JTAG interface.

We don't have any plans to change this arrangement in any of our future designs:
in the absence of 100% complete understanding of the internals of both chips,
there is no telling what unexpected gotcha may occur if the Iota chip is
included in the same scan chain as the Calypso, hence we are not doing that.

ARM7 and C54x DSP cores
=======================

The regular JTAG scan chain inside the Calypso goes through two TAPs
corresponding to the two processor cores.  The ARM7 TAP with a 4-bit IR is
closer to TDI, and the C54x DSP TAP with an 8-bit IR is closer to TDO.  The
debug interface to the ARM7 core through its respective TAP is consistent with
public ARM7TDMI documentation from ARM except for one important quirk described
below, but we know absolutely nothing about the DSP TAP and its debug protocol
other than how to put it into BYPASS so we can operate on the ARM.

It appears from passing references in some TI documents that they did intend to
have an ability to debug the Calypso DSP via JTAG "emulation", and TI's CCS
software working through TI's XDS510 or XDS560 hardware (the same setup that
successfully connects to the ARM7 part of the Calypso) supports C54x targets.
However, we have no idea how any potential JTAG access to the DSP would interact
with its reset control coming from the ARM or with its power saving modes, and
it is very likely that there are some security mechanisms restricting debug
access to the DSP (perhaps needing some secret key to unlock it), thus being
able to debug the DSP via JTAG is not something we can realistically hope for
unless we either buy out the complete chip design from TI or physically
reverse-engineer the chip transistor by transistor, both options being equally
cost-prohibitive.  At our current level of budgetary means, our ability to use
the JTAG interface on the Calypso is limited to the ARM7 part, not the DSP.

Non-standard extension to the ARM7TDMI TAP
==========================================

We know that TI made at least one non-standard extension to the ARM7TDMI TAP in
the Calypso because it implements at least one additional opcode that does not
appear in any public documentation from ARM.  When connecting to this ARM7
target, TI's CCS software working through XDS510 or XDS560 hardware apparently
scans a 0xB opcode (4'b1011) through the IR, and then apparently scans 2'b10
through the 2-bit DR selected by this opcode.  (I said "apparently" because so
far the only people who have actually sniffed the JTAG communications produced
by the XDS+CCS combo were OsmocomBB people, not anyone from the FreeCalypso
team, hence we don't have any authentic knowledge currently.)  Experiments with
OpenOCD show that the just-described sequence of IR and DR scans with an
unknown instruction and an unknown data register is necessary in order to allow
halting the ARM7 core: if we try to halt it in the standard ARM7TDMI way (either
via DBGRQ or via a catch-all breakpoint unit setup) without doing the magic
sequence first, no halt is effected.

Fortunately though, after we issue the non-understood magic sequence once, all
subsequent ARM7TDMI halt/resume manipulations done in the standard way appear
to work just fine, no more quirks.  The only time when the "halt unlock" magic
sequence needs to be repeated is after a reset, which is expected.

Interaction with the watchdog timer
===================================

The Calypso chip includes a watchdog timer feature; if this watchdog timer is
enabled and allowed to expire, it effects a fairly deep reset of the chip.  The
Calypso boot ROM code and most firmware designs do a step early on to disable
this watchdog, and it is not subsequently re-enabled except to effect a reboot
when so desired, but as the ARM7 core first comes out of reset and starts
executing instructions from the reset vector (whether ROM or external memory),
the watchdog timer is enabled and ticking.  This watchdog timer interacts with
JTAG as follows:

1) When the ARM7 core is halted via JTAG, the watchdog timer (if enabled) is
   NOT stopped or paused, but keeps ticking.

2) If a watchdog reset occurs while the ARM7 core is halted, everything goes
   out of whack, consistent with the note in standard ARM7TDMI documentation
   which says that a reset must not be applied to the core while it is in debug
   halt state.

Therefore, if the ARM7 core is to be halted at a time when the watchdog timer
is enabled and ticking, the halt operation must be quickly followed by two
system bus write operations (mwh command in OpenOCD) to the WATCHDOG_TIM_MODE
register, executing the watchdog disable sequence before the timer is allowed
to expire while halted.

JTAG clock speed
================

It is often stated that the JTAG clock speed must be no greater than 1/6 of the
system clock speed when talking to ARM cores, and that JTAG access is blocked
when the core goes into a power saving mode with the clock stopped.  Neither of
these constraints applies to our beloved Calypso though: the stated issues occur
in chip designs which internally synchronize JTAG signals including TCK to their
system clock, but Calypso and its predecessors don't do that, they use the hard
macrocell version of the ARM7TDMI core instead, use TCK directly to clock JTAG-
specific logic and perform "hard" clock switching for debug mode.

According to the available cal000_a.pdf document, the maximum TCK frequency
supported by the Calypso is 10 MHz, which also appears to be the only TCK
frequency which TI's older XDS510 "emulator" pods can produce without hardware
modifications.  This 10 MHz TCK frequency can be used no matter what frequency
is fed to Calypso's main CLKTCXO clock input or what frequency the ARM7 core is
configured to run at, and JTAG keeps working even when the main clock is
completely stopped.

It is possible to halt the Calypso ARM7 core when it is in a sleep mode, even
in deep sleep: manipulation of internal scan chain 2 to set DBGRQ is a JTAG-only
operation, contained entirely in the TCK clock domain, thus it works even with
the main VCXO stopped, and the actual halt occurs on wakeup when the ARM7 core
regains its regular clock and sees the internal DBGRQ signal asserted.

Halting immediately out of reset
================================

To me (Mother Mychaela) it always seemed evident that the Calypso and its
predecessors had to have some way to perform a "reset and hold still" maneuvre,
as this capability was absolutely essential for deterministic bootstrapping and
recovery of boards before the Calypso boot ROM subsumed that function.  However,
the exact manipulations required to achieve this effect have remained elusive
for a long time until I found the answer in May-June of 2019.  The trick is NOT
done through EMU0/1 pins like I once thought, and the method used on many other
chips involving classic TRST and SRST signals is clearly not applicable to the
Calypso given its very different reset structure.

The answer lies in the clocking architecture of TI GSM chipsets, involving a
VCXO that is started and stopped and a 32.768 kHz clock which is always running.
When the Calypso starts its boot process in response to the ON_nOFF signal
going from low to high (in the XDS-triggered test reset scenario this event
immediately follows the release of external reset), the main VCXO is off (i.e.,
it hasn't been started yet) and only the 32.768 kHz clock is running.  At this
point the ARM7 core receives no clock at all (the 32.768 kHz clock is never fed
to the ARM7), and the ULPD block (the same block that handles deep sleep) goes
through the sequence of first enabling the main VCXO, then waiting for it to
stabilize.  This sequence takes about 8192 cycles of the slow clock (about
250 ms), and only at the completion of this sequence the ARM7 core gets its
first clock.  But during that 250 ms time window the JTAG logic is out of its
reset and functioning, and it can be operated because Calypso JTAG does not
depend on the main ARM clock which is stopped.

The following sequence of steps successfully achieves the effect of resetting
the Calypso+Iota chipset and all board-level peripherals that are subservient
to it, and halting the Calypso directly at the reset vector before the first
instruction is executed:

1) Give the chipset a test reset pulse via the XDS_RESET line; the exact
   required duration is not known, but my OpenOCD-based proof of concept gives
   a 50 ms pulse.

2) Immediately after releasing the reset or after a short delay (my PoC does a
   10 ms delay), start exercising the JTAG scan chain, which has been fully
   reset - it will be responsive at this point.

3) Perform the "magic" IR and DR scans to enable halting ability, just like we
   do when we wish to halt an already-running Calypso.

4) Going through scan chain 2 inside the ARM7TDMI TAP, set the DBGRQ bit.
   All steps up to this one must happen before Calypso ULPD enables the
   VCXO-derived clock to the ARM7.

5) Also going through scan chain 2, poll and wait for DBGACK to get set,
   indicating that the ARM7TDMI core halted - this event will happen when the
   core gets its first clocks.

6) Once the ARM7TDMI core is halted, perform the two mwh operations to the
   0xFFFFF804 register (WATCHDOG_TIM_MODE) to disable the watchdog, otherwise
   it will generate another internal reset and mess up the system state.

We never found any built-in provision in TI's CCS (see below) or any script for
CCS that does the above, instead I (Mother Mychaela) found it on my own by
thinking about how it could possibly be done, and proved the idea working
with an OpenOCD setup presented in the freecalypso-hwlab repository.

Original official TI tools
==========================

TI's original and official tool for operating on Calypso JTAG was their Code
Composer Studio (CCS) software, working through TI's XDS510 and XDS560
"emulator" hardware.  The original hardware solution was the XDS510, and I mean
the original XDS510 which was an ISA card made by TI themselves, not any of the
later "XDS510-class" "emulators" made by companies acting as TI's 3rd-party
partners.  The next successor to this original XDS510 was the original XDS560,
also made by TI themselves and distinct from the later "XDS560-class" devices
by TI's 3rd-party partner companies.  The original XDS560 is a PCI card rather
than ISA, thus a little easier to get working in 2019, and also more readily
available on ebay.  Both XDS510 and XDS560 consist of a desktop PC card (ISA or
PCI) and an active pod, and the pod has a non-detachable target connection cable
coming out of it, terminating in a female connector mating with the TI-style
14-pin JTAG header.  The pod connector fits perfectly to TI's original D-Sample
board, but on our FCDEV3B it fails to fit because the JTAG and dual UART headers
are too close together.  Therefore, anyone who is interested in connecting TI's
original XDS510 or XDS560 to an FCDEV3B would need to get some male-to-female
jumper wires or make a custom-crimped interposer cable.

The version of CCS which we found to work with these "emulator" adapters (both
XDS510 and XDS560) and with Calypso targets is this one:

ftp://ftp.freecalypso.org/pub/GSM/TI_tools/CCS/CCS_3.3.83.20_win32.zip

In order to get this CCS to work with a Calypso target, you will need to create
a "custom board" configuration in CCS setup - none of the predefined board
configs shipped with CCS will work.  To create the needed "custom board" config,
select your "emulator" (XDS510 or XDS560), then add an ARM7 target and a
TMS320C5400 target in this order, which is the order from TDI to TDO.  With this
custom config saved, running CCS brings up what they call the Parallel Debug
Manager, which supposedly supports coordinated debugging of both ARM and DSP
cores.  However, I (Mother Mychaela) have not tried connecting to the DSP part,
only ARM7; another FreeCalypso community member who also got a working XDS510
setup talking to an FCDEV3B did try it, but saw what appears to be garbage.  As
discussed earlier in this article, we are completely in the blind here, hence
this direction is not being seriously explored at the present.

In order to play with just the ARM7 core, leaving the DSP alone, select the
ARM7 target in the Open menu in Parallel Debug Manager - the main CCS debug
window will then open, and it will be specific to the ARM7 target.  In my own
testing all further operations were done from the latter window and its menus.

Reset with TI's tools
---------------------

Both XDS510 and XDS560 "emulators" have only one reset output; on TI's general-
purpose DSP development boards outside of the GSM Skunkworks division this one
reset line was TRST, whereas on D-Sample and Leonardo boards (and on our
FCDEV3B) this signal is repurposed to drive Iota nTESTRESET through a clever
transistor circuit.  TI's general-purpose (non-GSM) DSP chips and boards have
internal pull-downs on TRST rather than pull-ups (JTAG logic permanently held
down in reset when no "emulator" is connected), hence both XDS510 and XDS560
pods drive this signal with an active push-pull driver - which is why Calypso
development boards include the special transistor circuit rather than connect
the XDS_RESET line (as we call it) directly to internal nTESTRESET.

Prior to initialization, a "cold" XDS560 pod has its reset output held low,
thus the target board will be held down in test reset and will appear completely
unresponsive.  To initialize the XDS560 and release it from reset, select
"Emulator Reset" from the Debug menu.  For this operation to succeed, the LDO
regulators in the Iota ABB need to be turned on, putting out 2.8 V on the V-IO
rail which is used as the target voltage reference by the XDS560 pod, so you
will probably need to press either the PWON button or the RESET button on the
FCDEV3B initially - and if the green LED stays off after that button press, you
know that the board is being held down in test reset by the XDS560 pod.  Then
do the "Emulator Reset" operation, at which point the green LED will turn on
and the board will boot normally.  From this point onward, doing a repeated
"Emulator Reset" operation causes a low-then-high pulse to be put out on the
XDS_RESET line, resetting the board and once again causing it to go through a
fresh boot.

Connecting to the ARM7 core and halting it
------------------------------------------

Once the XDS560 has been initialized and the target board has been lifted out
of test reset with the "Emulator Reset" operation, you can execute the
"Connect target" operation, also in the Debug menu.  This operation produces a
successful halt (I can only guess that this step is the point at which the
mysterious 0xB JTAG instruction and the unknown 2-bit register scan are issued,
unlocking the halting ability on this modified ARM7TDMI core), but the halt
happens at whichever point the ARM7 core happens to be in its code execution,
i.e., the generic, non-GSM-specific CCS has no knowledge of the peculiar timing
sequence that is required to achieve a halt directly out of reset on the
Calypso.  It is my (Mychaela's) guess that CCS probably has some scripting
ability for more advanced users, and that TI's GSM Skunkworks division used
this custom scripting mechanism to do a sequence of {Emulator reset, then
connect to target and halt, then execute two register writes to disable the
watchdog} with machine rather human timing between the steps.  Machine rather
than human timing is required in order to hit the 250 ms window between the
release of reset and the beginning of ARM core execution, and also to disable
the watchdog after the halt via two register writes before it goes off.

Using OpenOCD on Calypso targets
================================

Building on top of the work that was done almost a decade earlier by some people
in the OsmocomBB camp (they sniffed the magic "halt unlock" sequence from an
XDS+CCS setup and gained the ability to halt an already-running Calypso with
OpenOCD, albeit without the reset magic) and adding the more in-depth
understanding provided by Mother Mychaela, we now have the ability to use
OpenOCD with a simple FT2232D adapter (instead of TI's XDS+CCS) to connect to
JTAG on TI/FC development boards, both D-Sample and FCDEV3B, gaining the power
of Free Software instead of proprietary tools.  For the details, please refer
to the freecalypso-hwlab repository.