view doc/Loadtool-flash-support @ 854:74331b35b1da

ringtools/examples/ring.pwt: PWT equivalent of ring.buz
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 09 Nov 2021 16:39:52 +0000
parents 809829dbc58a
children
line wrap: on
line source

fc-loadtool is our tool for reading and writing the non-volatile flash memory
on all of our supported target devices, and the set of targets which it needs
to support keeps growing.  Here are some of the challenges we have to deal with:

* Some Calypso board designs use AMD-style flash, others use Intel-style flash.
  Initially we only supported AMD-style flash chips that were used in our first
  targets (Openmoko GTA02 and Pirelli DP-L10), then we got other targets that
  have Intel-style flash.  So far we have not yet run into a case where both
  kinds of flash can be encountered on the same target family, but our current
  design supports this possibility.

* All Calypso devices which we currently support have flash chips with non-
  uniform sector geometries, i.e., the area that would otherwise be the first
  or the last sector is subdivided into smaller sectors (erase units).  Both
  "top boot" (small sectors at high addresses) and "bottom boot" (small sectors
  at low addresses) geometries are found among our targets, as well as flashes
  that have small sectors at both ends.  The exact sector geometry needs to be
  known to the flash manipulation tool in order to perform correct flash erase
  and program operations.

* While most Calypso devices have a single flash chip providing a single bank
  of flash (can be as small as 2 MiB or as big as 8 MiB), some of our targets
  (our own FCDEV3B and the Pirelli DP-L10 phone from which the idea was copied)
  provide two flash chip select banks of 8 MiB each.  To make the matters even
  more complicated, all of that flash is actually a single 16 MiB chip that has
  two chip selects instead of one, specifically designed for processors like
  our Calypso that can only address a maximum of 8 MiB per chip select.

* It is a fixed target property whether a given board is wired for only one
  flash chip select or allows the possibility of dual-bank flash, and if a
  second flash chip select is provided for, which Calypso chip select it is
  wired to.

Given the existence of the CFI (Common Flash Interface) standard and the fact
that every flash chip we have encountered so far in a Calypso device does have
a readable CFI structure, one may naively think that the most sensible way to
support all of our possible flash configurations would be to read and parse the
CFI structure in a device-agnostic way (i.e., without special cases for specific
chip types) and thus support "everything".  But here are the problems with this
simplistic approach:

* On boards that have 16 MiB of flash in a Spansion S71PL129J or S71PL129N chip,
  it makes the most sense for us to treat this big flash as two separate banks
  of 8 MiB each - but the CFI structure describes a single 16 MiB flash chip.

* AMD-style flashes with "top boot" geometries are among our repertoire of
  devices to be supported, and they have their regions listed in the wrong order
  in the CFI structure - one needs to look in the AMD-specific part outside of
  the vendor-neutral geometry structure to see the true "top boot" geometry.

* Intel-style flashes with independent read/write partitions such that each
  partition has its own status register and its own "read array" vs. "read SR"
  state require special handling in our architecture, but autoconfiguring this
  quirk agnostically from CFI seems too difficult to me, and I wouldn't trust
  it.

Our previous architectural attempts
===================================

Initially we only supported two flash chip types, Samsung K5A32xx_T (Openmoko
GTA02) and Spansion S71PL129N (Pirelli DP-L10) with strictly manual selection:
-h gta02 selected one and -h pirelli selected the other via hardware parameter
files.  There was an ID check to prevent bogosity from wrong manual selection,
but no autodetection or autoconfiguration.  Then we added Compal target support;
aside from Mot C155/156 which has partition quirks that were only discovered
much later, these phones have simple Intel-style flashes without any of the CFI
problems listed above, thus they were handled via CFI.  Thus we had a hybrid
architecture: Openmoko, Pirelli and FCDEV3B targets were handled by way of
manual selection and ID checks to catch errors, whereas Compal targets were
handled by way of CFI-based autodetection and autoconfiguration.

Then it was discovered that the 8 MiB Intel-style flash on the D-Sample board
and on Mot C155/156 has partition quirks which our CFI-based autoconfiguration
(looking at vendor-agnostic geometry bits only) could not take care of, and the
solution was to move these targets from CFI-based autoconfiguration to the same
kind of fixed device selection and configuration as was used for AMD flashes.
At that point our flash handling architecture became a mess, and when I started
questioning how to extend it further as the need arises to support more
different flash chip types on a wide variety of Calypso targets, it became
clear that a redesign was needed.

Our current architecture
========================

In our current architecture the only flash configuration that is indicated
statically in the hardware parameter files (selected with the -h option,
practically meaning predefined target configurations) is board wiring
information.  There are 3 possibilities that can be configured:

flash single-4M base_addr		-- wired for 1 bank of up to 4 MiB
flash single-8M base_addr		-- wired for 1 bank of up to 8 MiB
flash dual-8M bank0_base bank1_base	-- wired for 2 banks of up to 8 MiB each

Naturally the dual-8M configuration only makes sense for boards that are wired
with a provision for a second flash bank, in which case the second bank base
address will depend on the board wiring, i.e., which Calypso chip select it is.
(Bank 0 base address will normally be 0x03000000, i.e., the alternate nCS0
mapping that needs to be used when the boot ROM is mapped at 0.)  The choice
between single-4M and single-8M needs to match whether or not the associated
init script includes a "w16 fffef006 0008" command to enable ADD22.

Beyond this board wiring configuration, the rest of flash support is based on a
hard-coded table of all supported devices (a table that can grow indefinitely)
plus autodetection amongst this supported set.  In other words, fc-loadtool will
only operate on a given flash chip if it explicitly knows about that chip, but
the set of supported chips can be indefinitely extended without hitting
architectural barriers, and our autodetection logic will detect and handle any
supported chip on any board target.

Autodetection details
=====================

The flash chip autodetection operation proceeds as follows:

* A sequence of writes is done to put the chip into the Read ID mode,
  equivalent to the following hypothetical C code with base_addr being an
  integer:

  *(volatile uint16_t *)(base_addr + 0xAAA) = 0xAA;
  *(volatile uint16_t *)(base_addr + 0x554) = 0x55;
  *(volatile uint16_t *)(base_addr + 0xAAA) = 0x90;

* 16-bit words at base_addr offsets of 0 and 2 (where the manufacturer and
  device ID codes are expected to reside) are read, and this ID is looked up in
  a table.  If the ID code is not known, we give up and don't allow any flash
  operations.

* For most ID codes, if we have found the code in our table, we know what device
  we should expect.  But before we go ahead and assume that the command set and
  the geometry are as we think based on the ID code, we also do a CFI check.
  Specifically, we put the flash chip into CFI query mode, read a defined set
  of word locations (can be different for each chip type), and require these
  words to match our compiled-in table.  Thus we guard against the possibility
  of some other flash chip having the same ID code (yes, there are known
  instances of ID code reuse) but having a different geometry.

* Some ID codes receive more complex handling.  Right now the only such case is
  Spansion PL-J/PL-N flash.  PL129J and PL129N flashes have different geometries
  and thus must be distinguished, but they have exactly the same ID codes and
  can only be distinguished by CFI.  We have CFI match tables for PL129J and
  for PL129N; we try to match the CFI bits provided by the chip against one
  table first, and if it fails to match, we try the other.  (As an optimization,
  we try the PL129N table first, as the N flash is the one found in real-world
  Pirelli DP-L10 specimen and used on our FCDEV3B.)  If the CFI matches neither
  table, we give up and don't allow any flash operations.

The end effect of this logic is that we err on the side of caution: we only
allow flash erase and program operations if we detect a flash chip which is
fully known to us and fully matches our expectations, with both the ID codes
and the CFI structure being as we expect.

Adding support for new flash chip types
=======================================

All supported flash devices are listed in the fldevs.c source module; new
devices that differ in geometry, command set or quirks need to be added there.
The description of each flash device in fldevs.c also includes the CFI table
that needs to matched to confirm the device in question.  A different module
named flashid.c contains the autodetection function and the table of device ID
codes; the latter table always needs to be extended, sometimes adding an
entirely new device, othertimes adding a newly found ID code for some flash
chip that is fully equivalent to an already supported one in terms of geometry,
command set and relevant quirks.

What do you do if you are an end user (not a FreeCalypso developer) and you got
a Calypso device whose flash chip is not being recognized by fc-loadtool?
Answer: you send the output of the "flash id" command (contains ID codes) and a
dump of the CFI structure to Mother Mychaela for analysis.  To make a dump of
the CFI structure, execute the following commands:

loadtool> w16 030000aa 98
loadtool> dump2bin 03000000 200 cfidump.bin

Handling of dual-bank 16 MiB flash chips
========================================

The Calypso can only address a maximum of 8 MiB per chip select, thus 16 MiB or
larger flash chips with a single chip select cannot be used in Calypso board
designs.  However, there are some special 16 MiB flash chips that present
themselves as two banks of 8 MiB each (even though the CFI structure describes
a single 16 MiB chip), and such flash chips are used on the Pirelli DP-L10 and
on our own FCDEV3B.

The flash handling architecture of fc-loadtool allows two banks to be configured
via a flash dual-8M setting in the hardware parameter file, and when that
configuration is used (-h fcfam and -h pirelli), the two banks are treated as
being entirely independent.  All regular flash commands operate only on the main
bank, and a parallel set of flash2 commands operates on the secondary bank.
The autodetection logic and the resulting configuration are done independently
on each flash bank when it is first accessed, thus fc-loadtool would happily
handle two separate flash chips of different types, even though such arrangement
is not expected to occur in any Calypso device.  But when a PL129J or PL129N
device is detected (the two dual-bank devices we currently support) on the
autodetection probe of either bank, the operating geometry is configured
appropriately based on which bank it is.

Primary flash bank mapping at 0x03000000
========================================

When loadagent runs on the Calypso target controlled by fc-loadtool, the Calypso
boot ROM will usually be mapped at 0, thus the alternate nCS0 mapping at
0x03000000 needs to be used for flash access.  However, the Calypso chip (all
versions we work with) has a little design bug in this part of the silicon:
this alternate nCS0 mapping at 0x03000000 works only when the debug visibility
bit in the API-RHEA control register (bit 6 in the FFFF:FB0E register) is set,
and does not work otherwise.  This bit is initially set as the Calypso comes
out of reset, and on most platforms we gain loadtool access via the boot ROM,
hence the problem does not occur - but on Compal targets we gain loadtool
access either through Compal's bootloader or via tfc139, and in both cases
Compal's fw (either the full fw or the bootloader part) has already set the
register in question to the runtime operational value of 0x2A (unchanged from
TI's TCS211 reference fw), with the debug visibility bit cleared, hence the
0x03000000 flash mapping no longer works.

There are two possible solutions: we can write into the FFFF:FB10 register to
disable the boot ROM and use the "regular" flash mapping at 0, which is what we
used to do, or we can write into the FFFF:FB0E register and re-enable the debug
visibility mode.  Right now we do the latter, allowing us to use the same
0x03000000 flash mapping on all targets for consistency.