FreeBSD/arm runs on the Atmel AT91RM9200, AT91SAM9260, AT91SAM9G20, AT91SAM9G45 and AT91SAM9XE-family. These are fairly flexible chips that allow hardware designers much flexibility in how it is connected to the rest of the system components. This flexibility is quite different than the uniformity found in the Wintel PC world.
How to get going on a KB9202B from Kwikbyte
This section tries to describe how to get going on a KB9202B board from Kwikbyte. The boards usually come with Linux and U-Boot preinstalled. This section will not explain how you replace that software with generic FreeBSD software. List of things we need:
- SD Flash card 512MB
- Ethernet cable
- Serial cable
- USB serial adapter
- FreeBSD sources
Building the FreeBSD software for ARM
http://people.freebsd.org/~xride/arm/
A tutorial on the AT91SAM9260-EK board for FreeBSD 91.-PRERELEASE can be found here
Fixing the rest
After that the kernel is built you need to install it somewhere that is reachable through TFTP. The following shell commands assume that your FreeBSD source directory is "/usr/src".
mkdir /tftpboot make -C/usr/src installkernel KERNCONF=custom \ TARGET_ARCH=arm DESTDIR=/tftpboot
Edit "/etc/inetd.conf" and enable the "tftpd" service on your build machine:
tftp dgram udp wait root /usr/libexec/tftpd tftpd -l -s /tftpboot tftp dgram udp6 wait root /usr/libexec/tftpd tftpd -l -s /tftpboot
Restart "inetd":
killall -HUP inetd
Loading the FreeBSD Kernel onto the KB9202B
When you boot the KB9202B board and connect to the serial port at 115200 baud you will eventually reach the U-Boot command prompt. Here you type in the following commands:
setenv serverip 10.0.0.251 setenv ipaddr 10.0.0.4 setenv ethaddr 4 tftpboot 0x20000000 boot/kernel/kernel go 0x200000E0
"10.0.0.251" is the IP of the computer running the TFTP server. "10.0.0.4" is the IP of the KB9202B board. Make sure that these IP's are on the same subnet.
Resulting messages on the serial console
KB9202B(www.kwikbyte.com) v2.5 U-Boot 1.1.4 (Oct 13 2006 - 15:42:03) DRAM: 64 MB Flash: 16 MB NAND: 32 MiB In: serial Out: serial Err: serial Hit any key to stop autoboot: 0 U-Boot> setenv serverip 10.0.0.251; setenv ipaddr 10.0.0.4; setenv ethaddr 4; \ tftpboot 0x20000000 boot/kernel/kernel; go 0x200000E0 TFTP from server 10.0.0.251; our IP address is 10.0.0.4 Filename 'boot/kernel/kernel'. Load address: 0x20000000 Loading: ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ############################################################## done Bytes transferred = 3644849 (379db1 hex) ## Starting application at 0x200000E0 ... KDB: debugger backends: ddb KDB: current backend: ddb Copyright (c) 1992-2007 The FreeBSD Project. Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD is a registered trademark of The FreeBSD Foundation. FreeBSD 8.0-CURRENT #25: Mon Dec 3 21:54:50 CET 2007 arm_freak@crossbuild.com:/usr/obj/arm/usr/7-current/src/sys/custom CPU: ARM920T rev 0 (ARM9TDMI core) DC enabled IC enabled WB enabled LABT 16KB/32B 64-way Instruction cache 16KB/32B 64-way write-back-locking-A Data cache real memory = 67108864 (64 MB) avail memory = 61485056 (58 MB) atmelarm0: <AT91 device bus> on motherboard at91_st0: <ST> mem 0xdffffd00-0xdffffdff irq 1 on atmelarm0 at91_st0: watchdog registered, timeout intervall max. 64 sec at91_pio0: <PIOA> mem 0xdffff400-0xdffff5ff irq 1 on atmelarm0 at91_pio0: ABSR: 0x60 OSR: 0 PSR:0x3938001f ODSR: 0 at91_pio0: [FILTER] at91_pio1: <PIOB> mem 0xdffff600-0xdffff7ff irq 1 on atmelarm0 at91_pio1: ABSR: 0xff301 OSR: 0x2 PSR:0x3fc00cfe ODSR: 0 at91_pio1: [FILTER] at91_pio2: <PIOC> mem 0xdffff800-0xdffff9ff irq 1 on atmelarm0 at91_pio2: ABSR: 0 OSR: 0x1000000a PSR:0xffffc075 ODSR: 0x10000000 at91_pio2: [FILTER] at91_pio3: <PIOD> mem 0xdffffa00-0xdffffbff irq 1 on atmelarm0 at91_pio3: ABSR: 0 OSR: 0 PSR:0xfffffff ODSR: 0 at91_pio3: [FILTER] at91_pmc0: <PMC> mem 0xdffffc00-0xdffffcff irq 1 on atmelarm0 at91_pmc0: Primary: 10000000 Hz PLLA: 180 MHz CPU: 180 MHz MCK: 60 MHz at91_mci0: <MCI mmc/sd host bridge> mem 0xdffb4000-0xdffb7fff irq 10 on atmelarm0 at91_mci0: [ITHREAD] mmc0: <mmc/sd bus> on at91_mci0 at91_twi0: <TWI> mem 0xdffb8000-0xdffbbfff irq 12 on atmelarm0 at91_twi0: [ITHREAD] iicbus0: <Philips I2C bus> on at91_twi0 setting cwgr to 0x1a4a4 iicbus0: <unknown card> at addr 0 iic0: <I2C generic I/O> on iicbus0 icee0: <I2C EEPROM> at addr 0xa0 on iicbus0 ate0: <EMAC> mem 0xdffbc000-0xdffbffff irq 24 on atmelarm0 ate0: No MAC address setdevice_attach: ate0 attach returned 6 uart0: <DBGU> mem 0xdffff200-0xdffff3ff irq 1 on atmelarm0 uart0: [FILTER].]X....½..½±..(115200,n,8,1) uart1: <USART0> mem 0xdffc0000-0xdffc3fff irq 6 on atmelarm0 uart1: [FILTER] uart2: <USART1> mem 0xdffc4000-0xdffc7fff irq 7 on atmelarm0 uart2: [FILTER] uart3: <USART2> mem 0xdffc8000-0xdffcbfff irq 8 on atmelarm0 uart3: [FILTER] uart4: <USART3> mem 0xdffcc000-0xdffcffff irq 9 on atmelarm0 uart4: [FILTER] at91_spi0: <SPI> mem 0xdffe0000-0xdffe3fff irq 13 on atmelarm0 at91_spi0: [ITHREAD] spibus0: <spibus bus> on at91_spi0 ohci0: <AT91 integrated OHCI controller> mem 0xdfe00000-0xdfefffff irq 23 on atmelarm0 ohci0: [ITHREAD] usb0 on ohci0 Cannot get 100 Hz clock; using 100Hz at91_st0: [FILTER] Timecounter "AT91RM9200 timer" frequency 32768 Hz quality 1000 Timecounters tick every 10.000 msec usb0: 12MBps Full Speed USB v1.0 uhub0: <Atmel OHCI root hub, class 9/0, rev 1.00/1.00, addr 1> on usb0 uhub0: 2 ports with 2 removable, self powered uhub0:uhub_explore: usb_new_device failed, error=USBD_SET_ADDR_FAILED uhub0:uhub_explore: device problem (USBD_SET_ADDR_FAILED), disabling port 2 mmc0: setting transfer rate to 30.000MHz Trying to mount root from ufs:/dev/mmcsd0s1a
Putting the FreeBSD kernel into flash memory
Now that you have test loaded your FreeBSD kernel, maybe you want to burn it into Flash? The following U-Boot commands will do that.
setenv serverip 10.0.0.251 setenv ipaddr 10.0.0.4 setenv ethaddr 4 tftpboot 0x20000000 boot/kernel/kernel
If you type the command "printenv" at the U-Boot command prompt you will see that the variable "$(filesize)" is already set to the size of the last transferred file. The commands below assume the your kernel size is less than 16MB! If your kernel size is greater than that you will have to do some modifications!
erase 0x10040000 0x1043ffff cp.b 0x20000000 0x10040000 0x$(filesize) setenv freebsd cp.b 0x10040000 0x20000000 0x$(filesize)\; go 0x200000E0 saveenv
Be aware that the "cp.b" command can take a very long time to complete. Next time the board ends up at the U-Boot prompt you simply have to type in:
run freebsd
Of course you can make your own command in the same manner. Have fun!
How to get USB working
Make sure that the USB port gets +5V power! Read the User Manual PDF for your board to find out what jumpers needs to be changed, if any. With regard to the kernel config you need at least:
device usb # generic USB subsystem device ohci # USB Host Controller Interface driver device at91_dci # USB Device Controller Interface driver
Additional useful USB drivers:
device usfs # device side USB flash disk driver device cdce # device and host side USB CDC ethernet driver device umass # host side USB flash disk driver
If the kernel config options above do not exist, have a look at src/sys/arm/conf/KB920X in your kernel sources.
The boot Loader
There are three main boot loaders and a bunch of minor ones (that are beyond the scope of this article). Redboot, uboot and FreeBSD's boot loaders are the three. Often times the board comes with one of these boot loaders and it is desirable to use that boot loader with FreeBSD.
FreeBSDat91UBoot contains the same for U-Boot. This is by far the most common boot loader for Atmel boards. Atmel places uboot on all its reference platforms.
FreeBSDat91Boot contains information about FreeBSD's "boot2" boot loader, including how to customize it for your given board. "boot2" is a primary boot loader (meaning it can be placed in the primary boot media and knows how to do the low level bring up of the CPU and memory). As such, it is by far the most primitive of the boot loaders available. However, it is designed to do one task very well and very fast in a minimum of space. This may make it ideal for some applications if you need minimal configuration or flexibility and maximum booting speed. Its use is generally discouraged unless you have a lot of experience writing bootstrap code for the early CPU execution.
Current Status
The FreeBSD/atmel port is being actively maintained. A number of companies have boards based on AT91RM9200 or the AT91SAM9 families of SoCs. Atmel recently gave one of the developers a new reference board for the AT91SAM9X25, and work is proceeding on that board. The AT91RM9200, AT91SAM9260 and AT91SAM9G20 SoCs are well supported by the base system. Additional work to make the SoC selection more modular is in progress.
SoC Modularization
Currently in the design phases, the SoC modularization work aims to make the addition of a new SoC nothing more than creating a bunch of tables, and, of course writing new drivers. Currently, much code needs to be duplicated to bring up a new SoC. Many of the interfaces in the system lack the fidelity of information to effectively operate in this scheme. A number of changes are needed.
Generic Board Support
Currently, only one board can be supported by any given kernel. All the particular details of the board are compiled into the kernel. The APIs that are used don't allow for multiple boards to be included. There's no way for a board init routine to query metadata from the boot loader about which board it thinks is present.
To combat the single board limitation, the arm port will be enhance to allow a number of boards to be compiled into a kernel. The boards will be listed in a linker set, and the platform specific code will iterate over this list, calling the board's init routine that matches the metadata from the loader.
The role of the board_init function will expand. Currently, on a very minimal set of actions are performed in the board_init function. In the future, the board_init function will communicate which devices are hard wired to the outside world, which GPIOs are used for what features, etc. Currently, there's no way to tell a device driver which pins are used for each of the functional pins that the driver is controlling. Currently, there's a lot of cut and paste code between the different board_init() functions. However, the current GPIO infrastructure is insufficient to make progress on this aspect of the problem.
GPIO Improvements
Currently, the interfaces between the board_init() and other parts of the kernel and the gpio system is based on a tuple of PIO unit base address and mask. This interface is somewhat cumbersome. It would be better to have a list of pin numbers rather than masks to operate on the PIOs. Registering interrupts for GPIO, selecting which peripheral to wire to a given pin, etc also needs to be refactored. Migration to using Atmel provided .h files also will make it easier to move to new SoCs, since we'll not need to generate these ourselves.
USART
Need to document the interface for board_init() to register USARTs.
EMAC
Need to document the interface for board_init() to register ethernet devices, both EMAC and MACB type.
SoC Generalization
Right now we have a lot of code that's cut and paste for each new SoC. However, this code could be table driven. The following items would need a table:
- Children Lists (along with the resources needed, and quirks)
- Pin assignments for each of the devices
- Interrupt priorities
- Clock configurations
- reset function
- delay function
Work is underway to move all of these things, and future support of SoCs to being 100% FDT driven from Atmel's FDT files.
Status of SoC
Chip |
Release Date (est) |
Atmel Status |
FreeBSD status / Notes |
AT91RM9200 |
2004 |
Retired, use AT91SAM9 parts |
Supported |
AT91SAM9260 |
2006 |
Retired, Replaced by AT91SAM9G20, AT91SAM9XE family |
Supported |
AT91SAM9261 |
2006 |
Mature Product, Replaced by AT91SAM9G10 |
Maybe |
AT91SAM9263 |
2006 |
Retired |
Unlikely |
AT91SAM9G10 |
2008 |
Production |
Maybe |
AT91SAM9G20 |
2008 |
Production |
Supported |
AT91SAM9R64 |
2009 |
Production |
Maybe |
AT91SAM9RL64 |
2009 |
Production |
Maybe |
AT91SAM9G45 |
2010 |
Production |
Supported |
AT91SAM9G46 |
2010 |
|
See AT91SAM9G45 |
AT91SAM9M10 |
2010 |
|
See AT91SAM9G45 |
AT91SAM9M11 |
2010 |
|
See AT91SAM9G45 |
AT91SAM9XE128 |
2010 |
Production |
Supported (Same as AT91SAM9260) |
AT91SAM9XE256 |
2010 |
|
See AT91SAM9XE128 |
AT91SAM9XE512 |
2010 |
|
See AT91SAM9XE128 |
AT91SAM9X25 |
2011 |
Production |
Preliminary Support |
AT91SAM9G15 |
2011 |
|
See AT91SAM9X25 |
AT91SAM9G25 |
2011 |
|
See AT91SAM9X25 |
AT91SAM9G35 |
2011 |
|
See AT91SAM9X25 |
AT91SAM9X35 |
2011 |
|
See AT91SAM9X25 |
AT91SAM9N12 |
2012 |
Production |
Not Yet |
AT91SAM9CN11 |
2013 |
Production |
Not Yet |
AT91SAM9CN12 |
2013 |
Production |
Not yet |
ATSAMA5D21 |
2015 |
Production |
Not Yet |
ATSAMA5D22 |
2015 |
|
see ATSAMA5D21 |
ATSAMA5D23 |
2015 |
|
see ATSAMA5D21 |
ATSAMA5D24 |
2015 |
|
see ATSAMA5D21 |
ATSAMA5D26 |
2015 |
|
see ATSAMA5D21 |
ATSAMA5D27 |
2015 |
|
see ATSAMA5D21 |
ATSAMA5D28 |
2015 |
|
see ATSAMA5D21 |
ATSAMA5D31 |
2013 |
Production |
Not yet |
ATSAMA5D33 |
2013 |
|
See ATSAMA5D31 |
ATSAMA5D34 |
2013 |
|
See ATSAMA5D31 |
ATSAMA5D35 |
2013 |
|
See ATSAMA5D31 |
ATSAMA5D36 |
2013 |
|
See ATSAMA5D31 |
ATSAMA5D41 |
2014 |
Production |
Not Yet |
ATSAMA5D42 |
2014 |
|
see ATSAMA5D21 |
ATSAMA5D43 |
2014 |
|
see ATSAMA5D21 |
ATSAMA5D44 |
2014 |
|
see ATSAMA5D21 |