I get asked lots of questions on how to build and deploy the kickstart loader and S1L to a new LPC32x0 based board. This topic will go through the procedure step-by-step for the FDI3250 and the PHY3250 boards on how to build the tools and program them to the board. It will also explain the things you need to change for a new board. The Phytec and FDI boards were chosen for this topic because they differ in the type of DRAM (SDR vs DDR), NAND device page size (small page vs large page), and primary bootloader deployment method (serial vs JTAG). The Embedded Artists board is also available, which provides a serial deployment method with DDR and large page NAND FLASH.
To get started, you will need a LPC32x0 based development board, the v2.01 release of the LPC32x0 Common Driver Library (CDL), a JTAG debugger (FDI3250 board), serial cable(s) for the board, and the CodeSourcery Lite GNU toolchain.
LPC3250 v2.01 CDL -> attached.
Future Designs (FDI) LPC3250 based board
Phytec LPC3250 based board
LPC32x0 bootloaders installation overview
The LPC32x0 CDL contains some basic examples, CPU startup code, board startup code for supported boards, basic drivers, bootloaders, and utilities for deploying the bootloaders into NAND FLASH, a serial EEPROM, or via the serial port. These bootloaders somehow need to be installed on the board. For development boards, it's possible to completely reprogram the board regardless of the boot devices state, if UART 5 is connected as the default bootup UART. This allows a tool called the serial loader tool to be used to download and program the boot device without the need for a JTAG debugger. If UART 5 isn't the default boot UART (or is not available at boot time), the boot device needs to be programmed via a JTAG unit or other method. A lot more information related to the LPC32x0 boot process can be found in the LPC32x0 User's guide. More information about the LPC32x0 boot process, the serial loader, and the startup code in the CDL can be found in the bottom of the page.
The Phytec board uses UART 5 as the default boot UART and will use the serial loader tool to setup the board's initial bootloader. The serial loader tool only works with UART 5 on the LPC32x0 devices, as UART 5 is the only UART supported for boot up in the LPC32x0's boot ROM.
The FDI board uses UART 1 as the default boot UART. Because UART 1 is not used by the boot ROM, it cannot be used with the serial loader tool. Instead, the bootloader software will be deployed to the board with the J-Link Lite LPC Edition JTAG debugger. The J-Link Lite LPC Edition is a low-cost JTAG debugger for LPC devices included with the FDI board. The Future Designs board included a LPC Edition of the J-Link Lite JTAG debugger. This debugger will be initially used to burn the kickstart loader and S1L? into the board's NAND FLASH. To use the debugger, first download the J-Link software from Segger's website at http://www.segger.com/cms/jlink-software.html. Install the software per the documentation and verify that the debugger can communicate with the board. J-link Commander doesn't requires a license to run with the LPC Edtition.
Bootloaders and burners
The CDL offers several bootloader options and a number of methods for deploying a bootloader to your board. There are several bootloader concepts involved here that are much better explained in the CDL startup code documentation.
A burner is an application that resides in the LPC32x0's memory and burns an image in another location into memory into the boot device on the board. The boot device may be NAND FLASH, a serial EEPROM or FLASH, or even NOR FLASH. The CDL contains 2 types of example NAND burner applications - MLC and SLC and burner applications for NOR FLASH (Phytec) and serial FLASH (Phytec). When burning an image to be booted from NAND FLASH, the MLC version must be used for the boot ROM to NAND load step. For all other NAND boot types, the SLC version must be used.
Kickstart and Stage 1 applications
The kickstart and Stage 1 applications are the common terms used with the LPC32x0 when talking about booting the LPC32x0. A kickstart (loader or bootloader) refers to a simple bootloader that is loaded and booted from the boot ROM which has the primary purpose of loading and booting another image. Any image loaded and booted via the LPC32x0 boot ROM has a size limit of about 54K, or 15.5K if booting from small page NAND FLASH. The kickstart loader always loads into IRAM at address 0x08000000. The kickstart loader usually performs some basic board functions such as initializing DRAM, clocks, GPIOs, etc. If the stage 1 application needed by the kickstart loader needs to be located in DRAM, the kickstart loader must initialize it prior to loading it.
A stage 1 applcation is an application that is loaded by the kickstart loader. The stage 1 application can be a Linux kernel, 3rd party bootloader, simple binary, or any other piece of code. The stage 1 application has no size limit and can be loaded anywhere in memory. Example stage 1 applications include u-boot, the CDL examples, the Stage 1 Loader (S1L), or eboot. The S1L application is commonly used as the stage 1 application with available 3rd party development boards, but it isn't needed.
It should be noted that the kickstart and stage 1 application concepts don't really apply to the LPC32x0 when booting from NOR FLASH, although a version of the kickstart loader and S1L are available for the NOR FLASH on the Phytec board that maintain the original approach when setting up to boot u-boot from NOR FLASH.
Depending on what you need, the best approach may vary. The table below helps explains different approachs to handling the bootloaders and application load.
|Boot method||Best approach|
|Booting an application > 54K with large page NAND FLASH|
Use a kickstart loader smaller than 54K that configures DRAM and clocking. Kickstart loader loads stage 1 application from NAND into DRAM and starts it. Kickstart loader is in block 0. Stage 1 application is in block 1 and on.
|Booting an application <= 54K with large page NAND FLASH|
Application can be stored in NAND block 0.
|Booting an application > 15.5K with small page NAND FLASH|
Use a kickstart loader smaller than 15.5K that configures DRAM and clocking. Kickstart loader loads stage 1 application from NAND into DRAM and starts it. Kickstart loader is in block 0. Stage 1 application is in block 1 and on. If the kickstart loader image cannot be built in under 15.5K, move the clock setup into the stage 1 application.
|Booting an application <= 15.5K with small page NAND FLASH|
Application can be stored in NAND block 0.
|Booting from serial EEPROM/FLASH|
Use a kickstart loader smaller than 54K that configures DRAM and clocking. Kickstart loader loads stage 1 application from the serial EEPROM/FLASH into DRAM and starts it. Kickstart loader is at the start of the EEPROM/FLASH. Stage 1 application isafter kickstart loader.
|Booting from NOR FLASH||NOR FLASH can be directly executed from and doesn't require pre-loading, so the kickstart/stage 1 application concepts don't apply.|
|Booting from the serial port||The image must always be 54K or less and loads into IRAM at address 0x08000000.|
Using burners to place bootloaders into the boot device
The burners are applications that simply burn another image into the boot device for the board. The CDL breaks up the burners into a kickstart burner and a stage 1 application burner.
The kickstart burner places the kickstart application as per the table below.
|Kickstart burner - NAND||Places kickstart loader into block 0 of NAND using the MLC NAND controller. Sets up the necessary boot information (ICR) for NAND boot the boot ROM needs.|
|Kickstart burner - SPI EEPROM/FLASH||Places kickstart loader into the start of a serial EEPROM/FLASH. Sets up the necessary boot information for SPI boot the boot ROM needs.|
|Kickstart burner - NOR||Burns a NOR verison of the kickstart loader into the start of NOR FLASH. Only needed if the conceptual kickstart/stage 1 application approach is used with NOR FLASH.|
The stage 1 application burner places the stage 1 application as per the table below.
|Stage 1 application - NAND||Places stage 1 application into block 1 and on of NAND FLASH using the SLC NAND controller. Note that in all NXP applications, the MLC controller is currently only used for the boot ROM.|
|Stage 1 application - SPI EEPROM/FLASH||Places the stage 1 application into the the serial EEPROM/FLASH after the kickstart loader.|
|Stage 1 application - NOR||Places the stage 1 application into the the NOR FLASH after the kickstart loader. Only needed if the conceptual kickstart/stage 1 application approach is used with NOR FLASH.|
As an example, to burn the kickstart loader into NAND FLASH, the kickstart burner must be loaded first. Once it has been loaded, the kickstart loader is loaded into a different location in memory. The kickstart burner then initializes NAND FLASH and burns the kickstart loader into block 0. The kickstart burner varies slightly in how it works with JTAG and serial loader methods. For the JTAG method, the kickstart burner and loader must be loaded as 2 different programs. For the serial loader mthod, the burner application loads the loader via the serial port via the serial loader tool. The serial loader method is the preferred method, but may not be optimal for production systems.
The entire process of burning the kickstart loader and stage 1 application has been covered before in the CDL bootloader topics. Once you have working verisons of the kickstart and stage 1 application burners, the kickstart loader, and the stage 1 application (S1L will be used in the examples following), you can use the Restoring the FDI3250 boot loaders for the FDI board and the Restoring the PHY3250 boot loaders for the Phytec board to get the images into the boards.
Is S1L needed?
S1L is an application usually loaded from the kickstart loader that allows other applications to be booted frmo SD cards, serial port, or NAND FLASH. It's also a very good tool for bringing up and testing new boards based on the LCP32x0. If you are developing a new LPC32x0 based board, the test functions built into S1L can be useful for testing DRAM and helping to locate possible DRAM configuration issues. If you are using or testing multiple operating systems (ie, WinCE and Linux), S1L can boot the u-boot and eboot loaders without alter NAND FLASH. The build procedure below assumes S1L will also be built and deployed.
Building the burners, kickstart loader, and S1L
Make sure you have the CodeSourcery Lite GNU tools installed and that you can run them from a CMD shell in Windows.
Download and install the LPC32x0 v2.01 CDL and navigate to the 'software' directory in a CMD shell window. If you are usnig the Phytec board, type 'setenv phy3250 gnu 1' to setup the build system for the Phytec board. FDI board developers should use 'setenv fdi3250 gnu 1'. See below for the Phytec setup.
You need to build 4 programs - the kickstart burner, S1L burner, kickstart loader, and S1L (from kick full) application.
To build the programs, type 'make' in the following directories in the CDL.
For the Phytec board,
.\software\csps\lpc32xx\bsps\phy3250\startup\examples\Burners\nand_sb\kickstart (Kickstart burner for small page FLASH)
.\software\csps\lpc32xx\bsps\phy3250\startup\examples\Burners\nand_sb\s1lapp (stage 1 application burner for small page FLASH)
.\software\csps\lpc32xx\bsps\phy3250\startup\examples\kickstart\kickstart_sb_nand (Kickstart loader for small page FLASH)
.\software\csps\lpc32xx\bsps\phy3250\startup\examples\s1l\s1l_from_kick_full (S1L for small page FLASH)
You should get 4 images as follows:
* burner_kickstart_nand_small_block_gnu.bin (kickstart burner)
* burner_s1app_nand_small_block_gnu.bin (stage 1 application burner)
* kickstart_nand_small_block_gnu.bin (kickstart loader)
* s1l_from_kick_gnu.bin (S1L (stage 1 application))
For the FDI board,
.\software\csps\lpc32xx\bsps\fdi3250\startup\examples\Burners\nand_lb\kickstart_jtag (Kickstart burner for large page FLASH)
.\software\csps\lpc32xx\bsps\fdi3250\startup\examples\Burners\nand_lb\s1lapp_jtag (stage 1 application burner for large page FLASH)
.\software\csps\lpc32xx\bsps\fdi3250\startup\examples\kickstart\kickstart_lb_nand (Kickstart loader for large page FLASH)
.\software\csps\lpc32xx\bsps\fdi3250\startup\examples\s1l\s1l_from_kick(S1L for large page FLASH)
You should get 4 images as follows:
* burner_kickstart_nand_large_block_jtag_gnu.elf (kickstart burner)
* burner_s1app_nand_large_block_jtag_gnu.elf (stage 1 application burner)
* kickstart_nand_large_block_gnu.bin (kickstart loader)
* s1l_from_kick_gnu.bin (S1L (stage 1 application))
Note that for the FDI board, there are elf files and bin files. The elf files are the burner applicaitons loaded via the JTAG debugger while the binaries are the payload applications to be used by the burner program (to be burned into NAND FLASH).
Modifying the CDL/BSP for a new target board
The burners, kickstart loader, and S1L can all be fairly easily to another board. In most cases, the porting process requires grabbing an existing BSP as a reference, modifying compile time defines for the board specific changes, and changing a little bit of existing code to support the new board. As most of the code is common to the burners, kickstart loader, and S1L - a change in one place usually applies to everything in the BSP.
The easiest place to start is to copy an existing BSP which has the supported features closest to the new board renaming the BSP to something else. The table below shows the current board BSPs in the CDL and the default support they provide. The BSps are located in the .\software\csps\lpc32xx\bsps\ directory.
|phy3250 (Phytec board)||Supports 64MB single data rate (SDR) SDRAM (32-bit configuration only), small page NAND FLASH, and UART 5 as the default boot UART, serial loader tool is used to burn images into the board|
|fdi3250 (FDI board)||Supports 32MB double data rate (DDR) SDRAM , large page NAND FLASH, and UART 1 as the default boot UART, JTAG must be used to burn images into the board|
|ea3250 (Embedded Artists board)||Supports 64MB double data rate (DDR) SDRAM , large page NAND FLASH, and UART 5 as the default boot UART, serial loader tool is used to burn images into the board|
Example: If I was developing a new LPC3250 based board that uses 64MB DDR memory, large page FLASH, and has UART 2 as the default UART port, I would make a copy of the fdi3250 BSP in the CDL's bsps directory, maybe renaming it to 'myboard3250'. If possible always start with an existing known working board BSP instead of using the generic BSP.
From the example above, the 'myboard3250'BSP will be used as the new target board for the example. The myboard3250 board has the following differences over the FDI3250 board.
* Uses 64MB of DDR instead of 32MB
* Uses 512MB of large page NAND FLASH instead of 256MB
What the new board will do
The new myboard3250 design will be used for running the Linux operating system. The system will boot from NAND FLASH and should boot into u-boot as soon as possible. As this is a new board, S1L can be used to temporarily setup and provide early board testing before deploying u-boot. S1L can either be permanently/temporarily setup as the application to boot from the kickstart loader or can be directly loaded from the serial port. We'll go through each option below.
Optional 1: Loading S1L directly via the serial port
S1L can be directly loaded into IRAM and executed via the serial port - if it's less than 54K in size. If you don't want to make a customer version of the tools for an S1L based configuration, but still want to do some initial DRAM and NAND testing with S1L before trying u-boot, building the IRAM version of S1L is the way to go. The
Optional 2: Using S1L to load and run u-boot
The currently supported development boards use the kickstart loader to load and run S1L. S1L in turn loads and runs u-boot. S1L runs inside of IRAM. This option is typical of current development boards.
End use case for the bootloaders
Ideally, we would like to have the LPC32x0 boot ROM boot directly into u-boot. Because u-boot is greater than 64MB and resides in SDRAM, we need to use the kickstart loader to initially boot the board from NAND block 0 (into IRAM) and then chain load the u-boot loader into SDRAM from NAND block 1. This requires a kickstart burner application, a burner for u-boot (u-boot is the stage 1 application in this case), and a kickstart loader that loads the stage 1 application (u-boot) in SDRAM.
Although this seems like the best place to start for a new board, it might be easier to start with S1L with either option 1 or 2. S1L has some built-in utilities for testing and helping to determine DRAM related issues.
BSP configurable items for startup code
For the v2.01 release of the CDL, some of the items that can be changed for the BSP include NAND timing and geometry, SDRAM type and timing, supported UARTs, locations of where the stage 1 application is stored in NAND FLASH and loaded in memory, and more. A complete list of items can be found in the CDL startup code documentation. The code typically also requires a few code changes to work correctly on new boards.
Setting up DRAM requires no new code - only the defines for DRAM timing and geometry we inherited from the copied code need to be modified to support the new board's devices. Locate the dram_configs.h file in the BSP and open it. Each define has a comment associated with it. Selecting the right values for these defines will allow the generic DRAM configuration code to properly configure the SDRAM. For the new board, I made the following change. If the part on the new board had different timing requirements, RAS/CAS latencies, a different mode word layout, or other differences, I would have to change a lot more.
/* Number of rows, columns, and bank bits for the SDRAM device */
#define SDRAM_BANK_BITS 2 /* 2 bits = 4 banks, 1 bit = 2 banks */
//#define SDRAM_COLS 9 // Deleted this line
#define SDRAM_COLS 10 // Added this line
#define SDRAM_ROWS 13
NAND driver modifcations part 1
The copied BSP already includes large page NAND FLASH drivers for the SLC and MLC. Several small changes need to be added to make these drivers work for the new board. NAND timing values need to be setup for the MLC and SLC controllers. These timings, in clocks based on the HCLK rate, need to be configured specifically for the NAND device and selected system clock rates. Once these are correctly setup, all of the applications that use NAND support will use these timing values. The values are shown below.
/* Timing setup for the NAND MLC controller timing registers. These
values can be adjusted to optimize the program time using the
burner software with NAND. If your not worried about how long it
takes to program your kickstart loader (or if your not using a
kickstart loader), don't worry about changing these values. If you
need to burn the kickstart, this can be speeded up by tweaking
these values. See the 32x0 user's guide for info on these
values. These should be programmed to work with the selected bus
(HCLK) speed - because the burn image is usually small (under 54K),
there really is not reason to change these values. */
#define MLC_TCEA_TIME 0x3
#define MLC_TWBTRB_TIME 0xF
#define MLC_TRHZ_TIME 0x3
#define MLC_TREH_TIME 0x7
#define MLC_TRP_TIME 0x7
#define MLC_TWH_TIME 0x7
#define MLC_TWP_TIME 0x7
/* Timing setup for the NAND SLC controller timing registers. On
systems using NAND, these values effect how fast the kickstart
loader loads the stage 1 application or how fast the S1L
application handles NAND operations. See the 32x0 user's guide for
info on these values. These should be programmed to work with the
selected bus (HCLK) speed. */
#define SLC_NAND_W_RDY 14
#define SLC_NAND_W_WIDTH 0x5
#define SLC_NAND_W_HOLD 0x2
#define SLC_NAND_W_SETUP 0x1
#define SLC_NAND_R_RDY 14
#define SLC_NAND_R_WIDTH 0x4
#define SLC_NAND_R_HOLD 0x2
#define SLC_NAND_R_SETUP 0x1
For the myboard3250 board, the NAND timings are unchanged.
NAND driver modifcations part 2
Each NAND device has a specific geometry associated with it used to setup access the device's blocks, pages, etc. This geometry needs to be supplied for each board. To setup this geometry, edit the board_mlc_nand_lb_driver.c and board_slc_nand_lb_driver.c files init() functions. If you only support one device, you can directly setup the values for the nandgeom structure based on the device's values. The original code inherited for this board checked several different NAND ID's and picked a geometry based on that configuration. For the myboard3250 board, only 1 configuration as shown below is supported.
nandgeom.num_blocks = 8192;
nandgeom.pages_per_block = 64;
nandgeom.data_bytes_per_page = 2048;
nandgeom.spare_bytes_per_page = 64;
nandgeom.address_cycles = 5;
Changing the CPU clock speed
The default CPU clock speed, bus (HCLK) speed, and peripheral (PCLK) speed can be setup in the setup.h file by altering the values shown below. The values - 266MHz CPU clock, 133MHz bus clock, 13.325MHz PCLK - are unchanged from the copied clock rates.
/* CPU speed in Hz */
#define CPU_CLOCK_RATE 266000000
/* HCLK bus divider rate - this can be 1, 2 or 4 and defines the HCLK
bus rate in relation to the CPU speed. This can never exceed
133MHz. DDR systems only work with a value of 2 or 4. */
#define HCLK_DIVIDER 2
/* PCLK divider rate - this can be 1 to 32 and defines PCLK bus rate
in relation to CPU speed. This value should be picked to allow the
PCLK to run as close as possible to 13MHz. Slightly exceeding 13Mhz
is ok */
#define PCLK_DIVIDER 20
Modifying GPIO states and pin muxing
GPIO states and pin muxing can usually be delayed until the main application starts. If any changes need to be made to pin muxing or GPIO states that should be done as soon as possible after boot, they can be made in the gpio_setup.c file. No changes will be made for this new board.
Default UART selection
The default UART used in S1L, kickstart, and the burner applications can be setup in the misc_config.h file. The FDI board uses UART1 as shown below. Only UART5 will work with the serial loader. Setting anything other than UART5 will allow UART output to occur as normal otherwise on that UART.
/* UART device and rate, supported UART devices are UART3, UART4,
UART5, and UART6 */
#define UARTOUTPUTDEV UART1
#define UARTOUTPUTRATE 115200
Setting load addresses for the burner applications and kickstart loader
The burner applications need to know where to load an image to be burnt into the boot device at some location in memory. Likewise, the kickstart loader needs to know where the stage 1 application needs to be loaded into memory. The addresses and sizes for the loader are specified in the misc_config.h file. The defaults are unchanged since S1L plans on being used.
#define BURNER_LOAD_ADDR 0x8000
#define BURNER_LOAD_SIZE (54*1024)
#define STAGE1_LOAD_ADDR 0x8000 /* Load at address 0x8000 */
#define STAGE1_LOAD_SIZE 0x20000 /* Load 128k */
The above values say that the burner applications (kickstart and stage 1 app burners) will load their image to be burned into NAND FLASH at address 0x8000 with size 54K and 128K, respectively. S1L is built to run at address 0x8000 and fits in under 128K. If I build the kickstart and S1L burners, the kicstart laoder, and S1L with these settings, the load addresses will be as follows:
* Kickstart and S1L burners load the image to burn into the boot device at address 0x00008000
* Kickstart loader loads and runs at adress 0x00000000 (will always run at address 0x00000000 unless built for NOR FLASH)
* S1L loads and runs at address 0x00008000. This is where the kickstart loader loads and places S1L. 128K will always be loaded regardless of the actual size if S1L stored in NAND by the stage 1 application burner.
Making a configuration for u-boot without S1L
If I wanted to make a bootloader configuration with the burners to have the kickstart loader directly load and run u-boot instead of S1L, I would make the following changes:
#define BURNER_LOAD_ADDR 0x80000000
#define BURNER_LOAD_SIZE (54*1024)
#define STAGE1_LOAD_ADDR 0x81F8000 /* Load at address 0x81F80000 */
#define STAGE1_LOAD_SIZE 0x40000 /* Load 256k */
Once I rebuild the burners and the kickstart loader (S1L isn't used, so it isn't built), I can use the kickstart burner with the kickstart loader and the stage 1 application burner with the u-boot.bin file. u-boot for the FDI board is normally built to load and run at address 0x81F80000. With the above changes, the following is done instead:
* Kickstart and S1L burners load the image to burn into the boot device at address 0x80000000 (larger DRAM area, won't fit in IRAM)
* Kickstart loader loads and runs at adress 0x00000000 (these values have nothing to do with the kickstart loader address)
* Kickstart loader loads stage 1 application (u-boot) into address 0x81F80000. The load size is 256K regardless if u-boot is actually smaller.
S1L configuration changes
If you do use S1L, look at the settings in the s1l_cfg.h file. The settings in this file are used to set the default S1L prompt string, S1L startup message, and the S1L NAND application storage area (used with the nsave, nload commands).
The CDL startup code documentation covers the startup code and it's various configurations very well. If possible, use a known working BSP in the CDL to start with when developing a new BSP for you board. The upcoming v2.02 release of the LCP32x0 CDL will have improved common code layout with no more board specific DRAM and NAND code, which should help a lot with porting the startup code to new boards.