User Tools

Site Tools


Linux on a Linksys WAG54G

N.B. this section is far from being complete and contains generally inaccurate information. It's just here for my note taking until I have worked things out properly. This has all been tested against a version 2 box, but should work with the almost identical version 3 as it just has twice the RAM and NAND space.

The idea of this page is to try and document my slow and irregular work to get Linux working on the Linksys WAG54G (version 2) without using the OpenWRT distribution.

My current work is downloadable at

New project for this based on buildroot called BRatWuRsT.

Misbehaving Ethernet Ports

Another gotcha is a broken capacitor (33uF 16V) can lead to all sorts of trouble. I had this issue with all threeten WAG54Gs I have bought off fleabay and found that with one of them I was able to get a temporary workaround by using a direct connection from my laptop by typing:

# ethtool -s eth0 autoneg off speed 10 duplex half

Partition Table

The onboard 4MB (64kB erase size) NAND is partition as follows.

partition start end size name
mtd0 0x900e0000 0x903f0000 3136kB rootfs
mtd1 0x90020000 0x900e0000 768kB kernel
mtd2 0x90000000 0x90020000 128kB adam2 bootloader
mtd3 0x903f0000 0x90400000 64kB adam2 cfg
mtd4 0x90020000 0x903f0000 3904kB kernel + rootfs

Under Linux the `ar7part.c` driver is meant to spit out a suitable partition table for both bootloaders (PSPBoot and ADAM2) that are available on the AR7 platform however it does not and should not be used; for me the 'rootfs' partition overlaps the 'linux' partition.

Serial Cable

The best serial port mod I have seen for the Linksys routers is done by placing a standard stereo 3.5mm headphone jack onto the front leg of the box (when making the hole, try to put it high up the leg otherwise the headphone socket will make contact with the internals). This makes for a very tidy setup, however what to plug into the headphone jack and how do you wire it up? Well FTDI make very nice serial cables that work great under Linux, including the TTL-232R-3V3-AJ which means you do not need to mess with a MAX-232 chip or soldering. The cabling inside I just hacked apart one of those old skool CD to soundcard cables which works perfectly.

Wiring it up could not be any easier, the pinout of the TTL-232R-3V3-AJ is available from their website and the pinout is shown below (shamelessly stolen from the old OpenWRT wiki); remember that when wiring you attach the TX pin of one end to the RX pin of the other and of course GND to GND.

|    __
|   |  |        <- Pin 1, GND
|    --
|   |  |        <- Pin 2, Not Connected
|    --
|   |  |        <- Pin 3, Router's Serial RX
|    --
|   |  |        <- Pin 4, Router's Serial TX
|    --
|   |  |        <- Pin 5, VCC [not used for serial port]
|    --
|   JP3
                Front of WAG54G

Once all hooked up, you should see some action when you load minicom and configure the serial port to run at 38400 8N1 with no hardware or software flow control.


To expose the pins, you just use the GPIO sysfs interface like so:

for I in $(seq 0 31); do echo $I > /sys/class/gpio/export; done

Then in /sys/class/gpio you should find a number of directories have appeared called 'gpioX' (where X is between 0 and 31).

You can browse the pin direction and values with:

# for I in $(seq 0 31); do echo -n "${I}: "; cat /sys/class/gpio/gpio${I}/direction; done
# for I in $(seq 0 31); do echo -n "${I}: "; cat /sys/class/gpio/gpio${I}/value; done

So far the map I have been able to piece together is (all pins have active_low set to zero):

GPIO pin number default direction default value Comment
0 in 1 fixed on
1 in 1 fixed on
2 in 1 fixed on
3 in 0 fixed off
4 in 0 status led {0/3}
5 in 1 status led {1/3}
6 in 1 wlan led
7 in 0 ?
8 in 1 status led {2/3}
9 in 0 ?
10 in 1 reset ethernet - CAUTION, it is a latch (0 - reset, 1 - start however lights lock on)
11 in 1 reset key (0 - off, 1 = pressed)
12 in 1 ?
13 in 1 ?
14 in 0 ?
15 in 1 fixed on
16 in 1 fixed on
17 in 1 fixed on
18 out 1 fixed on
19 out 1 fixed on
20 in 0 hw ver(?) {0/6}
21 in 0 hw ver(?) {1/6}
22 in 0 hw ver(?) {2/6}
23 in 1 hw ver(?) {3/6}
24 in 0 hw ver(?) {4/6}
25 in 0 hw ver(?) {5/6}
26 in varies ?
27 in varies ?
28 in 0 ?
29 in 0 ?
30 in 0 ?
31 in 0 ?

The status pin map looks like:

Pin Value 4 5 8 Comment
0 0 0 solid red
0 0 1 off
0 1 0 blink red
0 1 1 blink green
1 0 0 solid red
1 0 1 off
1 1 0 off
1 1 1 solid green

More Pins

Found that there are more GPIO pins lurking on the board:

/--- connector labeled JP4 --/
  [NC  ][NC  ]
  [3,3V][GND ]


Fortunately there is a full sized standard EJTAG 14 pin header lurking at JP1, only problem is that it is headless so you have to solder it on.

Once soldered though, you can hookup your JTAG tools of choice (I have the Flyswatter 2 with the ARM20 to MIPS14 converter) and fire up openocd (I used 0.70):

cat <<'EOF' > linksys-wag54gv2.cfg
# Linksys WAG54Gv2 Router (cloned from board/netgear-dg834v3.cfg)
# Internal 4Kb RAM (@0x80000000)
# Flash is located at 0x90000000 (CS0) and RAM is located at 0x94000000 (CS1)

source [find target/ti-ar7.cfg]

adapter_khz 100

# External 16MB SDRAM - disabled as we use internal sram
#$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 0x00001000

# External 4MB NOR Flash
set _FLASHNAME $_CHIPNAME.norflash
flash bank $_FLASHNAME cfi 0x90000000 0x00400000 2 2 $_TARGETNAME
openocd -f /usr/share/openocd/scripts/interface/ftdi/flyswatter2.cfg -f linksys-wag54gv2.cfg
Open On-Chip Debugger 0.7.0 (2013-08-31-18:07)
Licensed under GNU GPL v2
For bug reports, read
Info : only one transport option; autoselect 'jtag'
adapter speed: 100 kHz
Info : clock speed 100 kHz
Info : JTAG tap: ti-ar7.cpu tap/device found: 0x0000100f (mfg: 0x007, part: 0x0001, ver: 0x0)
telnet localhost 4444
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger

Resurrecting a Brick

You will require the ADAM2 0.22.12 bootloader blob, gunzip it and then enter the openocd console via telnet:

> flash list
{name cfi base 2415919104 size 4194304 bus_width 2 chip_width 2}

> flash banks
#0 : ti-ar7.norflash (cfi) at 0x90000000, size 0x00400000, buswidth 2, chipwidth 2

> halt
target state: halted
target halted in MIPS32 mode due to debug-request, pc: 0xb0000380

> flash erase_sector 0 0 1
erased sectors 0 through 1 on flash bank 0 in 1.369242s

> flash write_bank 0 adam2-0.22.12.bin 0
target halted in MIPS32 mode due to target-not-halted, pc: 0x80000088
target state: halted
[snipped lots of repeats of the previous two lines]
wrote 131072 bytes from file adam2-0.22.12.bin to flash bank 0 at offset 0x00000000 in 52.439411s (2.441 KiB/s)

> resume 0x90000000

You should now find your router booting.

Creating Firmwares

The process is very straight forward:

$ git clone
$ cd wag54g
$ ./go

On the first run the software will grumble that you do not have a configuration file and it will generate one for you. You should look at the file create local and amend it to your own needs. You will also need to create some account files, these have the name ssh.USERNAME and simply contain what you would normally expect in your ~/.ssh/authorized_keys file.

Once you have created at least one ssh.USERNAME file and amended the local configuration file, then just run go again. After an hour, you should have a firmware ready to use.

Flashing the Firmware

Seems that all the instructions relating to the WAG54G are different on the internet to the version of the ADAM2 bootloader that I have (version 0.22.12). I do not get the exciting option of FTP however I do get TFTP, which is available when the bootloader kicks in (you can give yourself a larger window of opportunity if you interrupt it by pressing any key over the serial port) with:

$ echo -e "mode binary\nconnect\nput firmware-code.bin" | tftp

The above command then flashes what is mtd4 in the partition table above.


$ export OPENWRT=$(git --git-dir=../openwrt/.git log -n1 | sed -n '/git-svn-id:/ s/^.*trunk@\([0-9]\+\) .*$/\1/ p')

$ # patch -p1 drivers/tty/serial/8250.c ../openwrt/target/linux/ar7/patches-2.6.37/500-serial_kludge.patch
$ # git commit -s -m "Apply [[OpenWRT]]@$OPENWRT Serial Kludge patches" drivers/tty/serial/8250.c

$ # do *not* apply the cpmac patches
$ # find ../openwrt/target/linux/ar7/patches-2.6.37 -type f -name '9*-cpmac*.patch' | xargs cat | patch -p1
$ # git commit -s -m "Apply [[OpenWRT]]@$OPENWRT CPMAC patches" -a

$ # tar c -C ../openwrt/target/linux/generic/files drivers/net/phy/{adm6996.{c,h},swconfig.c} include/linux/switch.h Documentation/networking/adm6996.txt | tar vx | xargs git add
$ # cat ../openwrt/target/linux/generic/patches-3.0/70* ../openwrt/target/linux/generic/patches-3.0/720-phy_adm6996.patch | patch -p1
$ # git commit -s -m "Apply [[OpenWRT]]@$OPENWRT ADM6996 patches" -a

Kernel Cooking Notes

A list of issues and hints I have found with the kernel:

  • CONFIG_CPMAC requires CONFIG_FIXED_PHY to function
  • CONFIG_FIXED_PHY needs to be compiled into the kernel
  • you can trim down your kernel considerably by compiling out CONFIG_BLOCK support. On the WAG54G, or any AR7 based platform, there is argubly no point having this support (as there is no way to connect a block device such as SCSI, USB, IDE, etc). For ages I was under the impression that to use JFFS2 you had to have CONFIG_BLOCK enabled so you could pass 'root=/dev/mtdblock0', however you can pass instead 'root=mtd0' which seems to be undocumented (in any JFFS2 documentation, however it is a function of the MTD subsystem)
  • if you use anything other than CONFIG_HZ_100, the timing delay loops go crazy; Florian thinks it is a bug in 4KEc stuff
  • CONFIG_CPMAC conflicts with anything other than CONFIG_PREEMPT_NONE if CONFIG_NO_HZ is set, reseting the box with no visible oops to trace the problem from when it initialises; only occurs if you have no PHY
  • you might need to apply the second part of the patch to 'drivers/serial/8250.c' from 500-serial_kludge.patch to make the serial console behave; this depends on the revision of your AR7 SoC, if the serial console looks a bit mixed up in places use this to fix it
  • for me the ar7part code is broken and so instead I add “mtdparts=physmap-flash.0:…..” to my kernel parameter list
  • for those wanting some kind of client NFS-esque support, I would recommend you look at 9p2000 and npfs as it only adds about 100kB of kernel modules to your kernel

Might be interesting for you, I use the following cmdline:

CONFIG_CMDLINE="mtdparts=physmap-flash.0:3136k@896k(rootfs),768k@128k(kernel),128k@0k(adam2)ro,64k@4032k(adam2-cfg)ro,3904k@128k(kernel+rootfs) rootfstype=jffs2 root=mtd0 rw"
wag54g.txt · Last modified: 2015/01/15 21:21 by alex