Running Embedded Linux on SuperH

by Bhavana Nagendra

With the proliferation of embedded architectures, companies are spending more money than ever to develop products utilizing embedded technologies. There is no doubt that there are numerous embedded architectures to choose from, like ARM, PowerPC, MIPS and SuperH. However, if price, performance, power and code density are required, then Hitachi SuperH is a good choice.

This article demonstrates running embedded Linux on the Hitachi SuperH target using Red Hat Linux and RedBoot as the boot loader. We discuss initial setup, related kernel details and copying the Linux kernel to Flash memory. We illustrate the appropriate use of JFFS2 and NFS filesystems and address some board-specific kernel issues with examples.

SuperH Solution Engine Boards

For the purpose of demonstrating the ease of using the SuperH base, we will use the Solution Engine family of development boards. Solution Engine boards make implementing SuperH-based designs easy and provide complete platforms ready for application development. The platforms provide spacious SDRAM and Flash memory to enable development of large and complex programs as well as rapid evaluation of the available peripherals. Though most of the discussion here is common to all SuperH targets, we will use the SH77x9 class of Solution Engines to illustrate the kernel and firmware.

Boot-Loader Environment

When working with embedded devices, a downloading and debugging environment to which the development machine can interface is a must. We use and recommend RedBoot for this purpose. RedBoot is a standardized embedded debug and bootstrap solution that provides firmware for running on embedded targets. It supports downloading and debugging of Flash and network booting of the Linux kernel, and downloading and updating of Flash images remotely via serial or Ethernet connections. There are ways to load Linux directly using the Hitachi boot loader (onboard monitor). However, using RedBoot as the firmware and boot loader is a lot friendlier.

Host Requirements and Target Setup

The development host must have an Ethernet port and an available serial port to connect to the target. A terminal emulator, such as minicom, can be used to communicate serially with the embedded board. You can use the hyperterminal or TELIX shareware program if you so desire. RedBoot can download a file via serial or Ethernet connections, though the latter is preferred for speedy downloads. A TFTP server must be set up on the network to which the SuperH target is connected, as RedBoot requires TFTP service for file downloading. This will ensure speedy kernel image and filesystem downloads.

Now, connect the host serially to the SuperH target via the board serial SCI connector. Plug the development machine and SuperH target Ethernet connections to a hub using a standard Ethernet cable. If the TFTP server is installed on the development machine, you can get away with connecting the target and host via a crossover Ethernet cable and creating a private LAN. This usually is preferred because the embedded system is isolated from the rest of the network. Use minicom to connect to the serial port with settings at 38400, 8N1. Turn both hardware flow control and software flow control off.

Assume for now that RedBoot is already running in Flash. We will discuss the process of reflashing the firmware later. The network configuration for the board is done in RedBoot. There are two ways of accomplishing this, either by using BOOTP or by configuring a static IP address. The BOOTP method would require the presence of a DHCP server in the same network. Below is an example of the SuperH board configured with a static IP address, where Default server IP address is the TFTP server IP address:

RedBoot> fconfig -l
Run script at boot: false
Use BOOTP for network configuration: false
Local IP address: 192.100.17.192
Default server IP address: 192.100.17.14
GDB connection port: 9000
Network debug at boot time: false

Instructions to configure the RedBoot environment are given at http://sources.redhat.com/ecos/docs-latest/redboot/configuring-the-redboot-environment.html.

Cross-Compilation Setup

The Red Hat Linux kernel supports a variety of boards, including the SuperH Solution Engine. Download the latest source RPM from the Red Hat FTP site (ftp://ftp.redhat.com/pub/redhat/linux/rawhide/SRPMS/SRPMS/). Install the kernel RPM and execute the spec file to install the kernel tarball. For a quick start define architecture and toolchain target triplet in the Makefile to cross-build for SuperH:

ARCH := sh
CROSS_COMPILE = sh-linux-gnu-

Configure the kernel using make xconfig with the system type Solution Engine and processor type SH7709 and build a compressed zImage binary:

make dep; make clean; make zImage.

Now, a few words regarding the various Solution Engine boards is in order. There are several incarnations of Solution Engine 7709 targets, and we have found architectural differences. The embedded device programming is such that chip differences would require software modification. Onboard memory differences like SDRAM vs. EDORAM would warrant changes to the firmware. We encountered some problems due to hardware differences between 7709R and the rest of the Solution Engines. The board was so different that kernel and driver changes were required for it to boot. I would like to mention two of those issues to illustrate the nature of the problems and depth of possible code changes.

The Solution Engine setup could not turn off all interrupts effectively at startup. This was because of interrupt layout differences. So the interrupt corresponding to the Ethernet controller remained enabled. When Linux initialized its interrupts, the interrupt pertaining to the Ethernet controller arrived. Since it was too early in the boot process and the Ethernet controller was not yet initialized, the interrupt could not be serviced, and as a result the target hung.

The solution was to disable the interrupt and reset the Ethernet controller with the reset_enet() function. There is no doubt that there are more elegant ways of solving this, but there is no denying its nastiness:

static void reset_enet(void)
{
  *(volatile unsigned short *) PA_83902_RST = 0;
  __delay (500);
  *(volatile unsigned short *) PA_83902_RST = ~0;
  __delay (500);
}

Next, the target dropped DHCP requests due to a misconfiguration of the buffer values. The problem was in the processing between the RAM buffer and Ethernet controller. The Ethernet controller driver required a different start page in the transfer buffer and stop page in the receive buffer, different from what was defined. Also, the related IRQ was different on this board and had to be configured specifically for the 7709R target.

Flashing the Kernel Image

Downloading the kernel onto the Hitachi board can be achieved via TFTP using RedBoot as the downloading and flashing interface. If the TFTP service is not set up on the development machine, then transfer the kernel image to the TFTP server. The image has to reside in the /tftpboot directory, though this is configurable. The board must be configured with an IP address for effective image transfer.

Turn on the target power switch for the RedBoot prompt. The IP address and TFTP server addresses already are set. At the RedBoot prompt, type help to look at the list of available commands and syntax. Below is the RedBoot banner and network setup:

RedBoot> DP83902A - static ESA: 08:88:12:34:56:78
IP: 192.100.17.132, Default server: 192.100.17.14
Using DNS server at 192.100.17.10
RedBoot(tm) bootstrap and debug environment [ROM]
Non-certified release, version R1.30 - built
  17:54:50, Oct 18 2001
Platform: SE77X9 (SH 7709R)
Copyright (C) 2000, 2001, Red Hat, Inc.
RAM: 0x8c000000-0x8e000000, 0x8c016c40-0x8dfdf000
     available
FLASH: 0x80000000 - 0x80400000, 32 blocks of
       0x00020000 bytes each.

We will use RedBoot Flash commands to copy the kernel and filesystem images onto the SuperH target Flash memory. This is a two-step process and can be accomplished by first loading the kernel image from the TFTP server onto a predetermined location on RAM and then transferring the kernel image from RAM to Flash. If you have an existing kernel on Flash, delete it. To load the kernel image we need to be aware of the load address. Either an uncompressed ELF vmlinux image or compressed zImage can be loaded, but keep in mind that the load address will be different. This address is determined by the value of CONFIG_MEMORY_START in the kernel configuration. The compressed zImage is loaded at the specified address location and will be decompressed and run from a different location depending on the available memory chunks in RAM. Compressed zImage is preferred over the vmlinux image as it occupies less space in Flash.

Here is an example of the load addresses for vmlinux and zImage with reference to the memory start address:

CONFIG_MEMORY_START = 0x0c000000
zImage start address = 0x0c021000
vmlinux start address = 0x0c001000

By converting the ELF kernel image to an S-record using the target-specific objcopy, it can be loaded without specifying an address:

sh-linux-gnu-objcopy -I sh-elf32 -O srec vmlinux
vmlinux.srec
Once the load address has been determined and kernel image loaded to RAM, the image can be copied to the Flash partition using RedBoot Flash commands to create a persistent image. First, we check available Flash space:
RedBoot> fis free
0x80020000 .. 0x803C0000
In our example, the size of kernel image is 0x84569, and it will be rounded up to 0x90000.

Next, we load the kernel image from the TFTP server:

RedBoot> load -r -b 0x8c210000 -m TFTP
-h 192.100.17.14 zImage

Finally, we write the kernel image onto Flash:

RedBoot> fis create -b 0x8c210000 -l
<
-r 0x8c210000 linux
Filesystem Choices

With the kernel now in Flash, there are a couple of different choices for the filesystem. Since the SuperH target has an onboard Ethernet, we can use NFS and mount the filesystem over the network at boot time. This choice is preferred because the size of the filesystem theoretically is only limited by the size of the hard disk on the NFS server. But access to an NFS server, a DHCP server and a network connection are a must. NFS root filesystem and a method of autoconfiguration like DHCP must be enabled in the kernel configuration for the NFS filesystem to work. The choice of autoconfiguration will depend on the target network.

If the filesystem has to be self-contained on the device Flash memory, then the JFFS2 filesystem should be used. JFFS2 is a log-structured filesystem specifically designed for use on Flash devices in embedded systems. Older Flash solutions used a translation layer on Flash devices to emulate a hard drive. JFFS2 places the filesystem directly on the Flash chips.

JFFS2 source code is included in the Red Hat Linux source starting from kernel release 2.4.10. If there is a need to update the JFFS2 source, the latest JFFS2 code can be downloaded from the Memory Technology Device (MTD) CVS tree at http://www.linux-mtd.infradead.org/. To obtain an up-to-date copy, type:

cvs -d :pserver:anoncvs@cvs.infradead.org:/home/cvs
login (password: anoncvs)
cvs -d :pserver:
co mtd

The mkfs.jffs2 utility is in the /util directory of the mtd tree.

JFFS2 filesystem must be enabled in the kernel image for this method to work. Solution Engine targets usually come with 4MiB of Flash. After loading RedBoot and the Linux kernel image we realistically would be left with about 3MiB Flash for the filesystem. The root filesystem image has to be created using the mkfs.jffs2 utility. Execute the command

mkfs.jffs2 -e 0x40000 -p -o /tmp/root.jffs2

in the target filesystem directory to create the root filesystem.

We first check available Flash space before copying the kernel:

RedBoot> fis free
0x800C0000 .. 0x803C0000

In our example, total free Flash is 0x300000 and the size of fs is 0x2c0000.

Then, we load the filesystem image from the TFTP server:

RedBoot> load -v -r -b 0x100000 -m TFTP
-h 192.100.17.14 root.jffs2

Next, we erase the Flash partition for the filesystem:

RedBoot> fis erase -f 0x800C0000 -l <total free Flash>
Finally, we write and create the filesystem image onto Flash in that order:
RedBoot> fis write -b 0x100000 -l <size of fs>
-f 0x800C0000
RedBoot> fis create "jffs2" -n -f 0x800C0000
-l <total free Flash>
How to Boot the Kernel

If using the NFS filesystem, load the kernel from Flash into memory. Execute the kernel in memory location 0x8c210000, passing in the NFS server IP address with the mountpoint as the kernel argument. The kernel argument can be configured into the kernel configuration in some embedded Linux kernels like ARM. However, the SuperH kernel doesn't allow for such configuration. Listing 1 shows the process of booting the Linux kernel in Flash.

Listing 1. Booting the Linux Kernel in Flash

If using the JFFS2 filesystem, the execute command is different and doesn't require as many kernel arguments. The mtdblock partition number is used to pinpoint the exact location of the filesystem in Flash. This partition number has to be passed correctly in for the kernel to boot successfully and display the login prompt. If the mtdblock number is incorrect, then the kernel cannot locate the filesystem.

RedBoot> fis list
Name       FLASH addr Mem addr   Length     Entry point
RedBoot    0x80000000 0x8C100000 0x00020000 0x80000000
RedBoot    0x80020000 0x8C020000 0x00020000 0x8C020000
[backup]
RedBoot    0x803C0000 0x803C0000 0x00001000 0x00000000
config
FIS        0x803E0000 0x803E0000 0x00020000 0x00000000
directory
linux      0x80020000 0x8C210000 0x000A0000 0x00000000
jffs2      0x800C0000 0x800C0000 0x00300000 0x00000000

Here is a simple ad hoc method to figure the mtdblock number for Hitachi Solution Engines. Look into the Flash partition table; the partitions are numbered consecutively starting at 1, excluding RedBoot[backup]. This results in jffs2 being mtdblock5. Even though the ad hoc method is quick, the safest way to ascertain the mtdblock number is to turn on debug in the MTD subsystem, rebuild the kernel and when the kernel boots up, a numbered partition table is printed out.

Here's how to load and execute the kernel:

RedBoot> fis load linux
RedBoot> exec -b 0x8c001000 -c "console=ttySC1,38400
root=/dev/mtdblock5 mem=32MB" 0x8c210000

Bigger applications that didn't fit on Flash, or those that are not required to boot the kernel successfully, can be accessed via NFS mount. Of course, this would require the target to have access to an NFS server.

Reflashing RedBoot

RedBoot is extremely target-specific, as it's important to maintain the size of the firmware. We need to use the RedBoot that is meant to run on our specific board. RedBoot uses the serial ports ttyS0 and ttyS1. The default settings are 38400 baud, 8N1 with both flow controls turned off. The Solution Engine ships with the Hitachi boot monitor in EPROM, which allows for initial programming of RedBoot.

Here is a description of how to reflash RedBoot to a SuperH target. First, set up the switches so that the board boots from EPROM. For most Solution Engines this would be SW4-3 and SW4-4, both turned on. However, there are exceptions like the 7709R; refer to the user manual for target-specific information.

Next, connect a serial cable to ttyS1 and power up the board. The target boots up the onboard monitor. Then, we invoke the Flash download command:

Ready> fl 21000000

The monitor should ask for input:

Flash ROM data copy to RAM
Please send an S-format record
Next, copy the RedBoot ROM S-record to the serial port. Because the processor speeds between the development machine and the SuperH target could be different, using
cat redboot.rom.srec > dev/ttyS1
would result in byte loss. To avoid this, use this TCL script to copy the file to the serial port:
#!/usr/bin/tclsh
#!/bin/sh
while { 0 <= [gets stdin line] } {
    puts "$line\r"
    after 100
}
script.tcl < redboot.srec > /dev/ttyS1
Eventually, the copy will complete with this message from the monitor:
Start Addrs = A1000000
End Addrs = A1xxxxxx
Transfer Complete
Finally, ensure that the target boots from Flash by flipping the switch SW4-3 to OFF (check the user manual for target-specific information). The next reboot should bring up the RedBoot banner.
Conclusion

Hopefully this article aids in the task of running firmware and the Linux kernel on a SuperH target. There is no one-size-fits-all when it comes to embedded systems, and that's certainly true with SuperH targets. However, SuperH is a very viable target for embedded Linux development, and the combination of SuperH and Linux results in a technically sound solution.

Resources

Bhavana Nagendra is a senior engineer for Red Hat, Inc. She is involved in embedded Linux design and development for a variety of architectures. She received MS degrees in Electrical Engineering and Computer Science from The Ohio State University. Bhavana welcomes comments or questions and can be reached at nagendra@redhat.com.

Load Disqus comments