Find special GPIOs

The TP-Link CPE510, a nice outdoor device, got a bad rx behaviour when using it with LEDE. I want to give a short overview how to debug those problems. It could also help you finding problems when facing ath9k pci cards.

To get down to the device. The CPE510 based on a AR9344 SoC. The integrated wireless part is supported by the ath9k driver. To get more knowledge about the AR9344 you should take a look into the public available datasheet. (google for ar9344 datasheet ;)

The AR9344 supports using GPIOs for special purposes it's called a GPIO function. If the function is enabled, the gpio is internally routed to the special purpose. Now the simple part comes if you know which register to look into, just look into it.

After reading the pages 52/53 of the datasheet, it's clear that it can route everything signal to every gpio. Remember the table, because it explains what value means what it's routed to the gpio. We suggest LNA are missing because the receiving part of the CPE510 is bad. So the value 46 and 47 are the important ones, 46 LNA Chain 0, 47 LNA Chain 1. LNA stands for low noice amplifier.

Now we know how the GPIOs works, let's find the register controlling the GPIO function. The GPIO section start at 130, but the interesting part is the GPIO IO Function 0 register at address 0x1804002c. It give you 8 bit to describe it's function, if it's 0x0 no function is selected and the GPIO is used as normal output. So if you write 46 into the bit 0-7 you set the GPIO to become the LNA Chain 0 signal. Every GPIO from GPIO0 to GPIO19 can configured using those register.

We know what registers are interesting (0x1804002c - 0x1804003c). We know which values are interesting (decimal 46 and decimal 47).

But how can we read out those value from a running system? First answer I hear is JTAG, but JTAG isn't easy to archive and more difficult to use on ar71xx, because the bootloader usally deactivate JTAG as one of the first commands.

But we can ask the kernel. /dev/mem is quite usefull for that. It's a direct way to the memory, very dangerous, but also handy ;). The easiest way to interface with /dev/mem is the simple utility called devmem or devmem2. To compile a compatible devmem2 you should use the GPL sources of the firmware, but you can also download the binary from here [1].

Copy devmem2 to /tmp via scp and start reading the values. Because mips is a 32bit architecture we have to read the register

Back to our LNA value. 46 and 47. In hex are those 0x2E and 0x2F. We have to look for those values aligned to 8bit.

# ./devmem2 0x1804002c
/dev/mem opened.
Memory mapped at address 0x2aaae000.
Value at address 0x1804002C (0x2aaae02c): 0x0
# ./devmem2 0x18040030
/dev/mem opened.
Memory mapped at address 0x2aaae000.
Value at address 0x18040030 (0x2aaae030): 0xB0A0900
# ./devmem2 0x18040034
/dev/mem opened.
Memory mapped at address 0x2aaae000.
Value at address 0x18040034 (0x2aaae034): 0x2D180000
# ./devmem2 0x18040038
/dev/mem opened.
Memory mapped at address 0x2aaae000.
Value at address 0x18040038 (0x2aaae038): 0x2C
# ./devmem2 0x1804003c
/dev/mem opened.
Memory mapped at address 0x2aaae000.
Value at address 0x1804003C (0x2aaae03c): 0x2F2E0000

Found it in 0x1804003C. LNA 0 is GPIO 18 and LNA1 is GPIO 19.