LeapPad Explorer Reversing

One drawback of all of my recent work and travel is less time for other pursuits. Case in point: It has been a long, long time since I did any serious hacking. And like any habit, after a while, the ‘jones’ gets to be too much to bear.

Last night I succumbed.

I found out from the good people on irc (freenode #Didj) that our friends at LeapFrog have released a 3rd generation of Linux-based handheld toys powered by the now-venerable ARM926EJ-S-based LF1000 CPU (aka Pollux):  The new device, a tablet handheld called LeapPad Explorer (code name Madrid) has a 5-inch LCD, a built-in camera, boots off of eMMC connected to the SD controller (instead of NAND Flash as in prior devices) and adds an accelerometer to the mix. The mini tablet form-factor makes this an interesting candidate for alternate uses. (Portable o-scope or logic analyzer? G-force meter? True-to-scale tall-screen arcade emu handheld?)

Curiosity got the better of me and before I knew it I was in my local big-box retailer shelling out hard-earned dinero for fresh pristine hardware, ripe for reversing.

A night’s work ensued, including sweeps with a continuity checker, a little de-soldering, some conformal coating stripper to soften the epoxy around the CPU and, finally, some hot-and-heavy action with a heatgun to reflow and remove the CPU. (The epoxy made chip-removal less than optimal, so some of the BGA balls didnt make it, but at least we can follow the traces.)


What we've found thus far:

UART Serial on the cartridge socket. UART is on the same pins as on previous LF1000 devices, which claude first documented on Didj way back when; so Moogle's DJHI breakouts will probably work fine. (I haven’t tested this yet) Edit: If at first the device doesn't boot with DJHI inserted,  simply re-seat the DJHI and try again.

UART Serial on J5 – VCC, Rx, Tx, Gnd  - this looks to be similar to the J5 on the Leapster Explorer.

JTAG – nicely labeled, right there on the silkscreen – and a big shoutout and props to the LeapFrog engineer(s) responsible for labeling the pads. Thank you. Your spot in heaven is assured. :) 

TVOut – TP125 is linked to good ol’ BGA grid square A2. Having gotten composite video working on Didj and Leapster Explorer devices I have a soft spot in my heart for this test pad. (Traced, but not tested, stay tuned...)

USB - The pin header, J34, to which the camera was attached, is USB Device. Pins 2 and 3 on J34 are D+ and D-. Pin 4 is GND and Pin 5 (square) is VCC. 

Here are the mainboard scans for the front and rear (and the rear following removal of the CPU and cartridge socket).


Creative Commons License
Images/content licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.



Augen eGo (Pollux) Linux shell and SD Card support

Managed to get to a Linux shell prompt by UART booting a zimage based on the Leapster Explorer kernel source and an initramfs containing a custom rootfs and modules that support SD/MMC cards.

The kernel module setup needs more refinement...

LF1000 # go 1800000
## Starting application at 0x01800000 ...
Uncompressing Linux............................................................................................................................................... done, booting the kernel.
Linux version 2.6.31-leapfrog (mgold@mgold-garage) (gcc version 4.4.3 (GCC) ) #40 Sat Nov 13 01:16:54 EST 2010
CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177
CPU: VIVT data cache, VIVT instruction cache
Machine: ARM-LF1000
Warning: bad configuration page, trying to continue
Memory policy: ECC disabled, Data cache writeback
lf1000_oscvco_set.50  changing pll 0, old=0x00250001, new=0x00496300
PLL0=532.500000 MHz   
lf1000_oscvco_set.50  changing pll 1, old=0x00348E01, new=0x0024C402
PLL1=147.000 MHz   Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 27940
Kernel command line: init=/bin/busybox console=ttyS0,115200 mem=110M
PID hash table entries: 512 (order: 9, 2048 bytes)
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 110MB = 110MB total
Memory: 106780KB available (2684K code, 314K data, 1608K init, 0K highmem)
TIM0=  4.593 MHz   TIM1=  4.593 MHz   TIM2=  4.593 MHz   TIM3=  4.593 MHz   TIM4=  4.593 MHz   
console [ttyS0] enabled
Calibrating delay loop (skipped) preset value.. 1065.00 BogoMIPS (lpj=5325000)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
NET: Registered protocol family 16
bio: create slab  at 0
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
NET: Registered protocol family 1
arch/arm/mach-lf1000/gpio_main.c.check_for_touchscreen:1346 X2 == high, no touchscreen
Reading Board ID =  0
msgmni has been set to 208
alg: No test for stdrng (krng)
io scheduler noop registered
io scheduler deadline registered (default)
Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing disabled
serial8250: ttyS0 at MMIO 0x0 (irq = 10) is a 8250
serial8250: ttyS1 at MMIO 0x0 (irq = 34) is a 8250
serial8250: ttyS2 at MMIO 0x0 (irq = 35) is a 8250
serial8250: ttyS3 at MMIO 0x0 (irq = 36) is a 8250
brd: module loaded
loop: module loaded
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
hcd->regs: xc706e000
before ohci_hcd_init()
after ohci_hcd_init()
lf1000-ohci lf1000-ohci: LF1000 OHCI
lf1000-ohci lf1000-ohci: new USB bus registered, assigned bus number 1
lf1000-ohci lf1000-ohci: irq 28, io mem 0xc000d000
ohci->regs: xc706e000
&ohci->regs->control: xc706e004
ioread32(&ohci->regs->control): 0x0
after hcd->driver->start
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
usb_add_hcd() returns 0
after usb_add_hcd()
usb_hcd_lf1000_probe returns
IRQ 31/lf1000-rtc: IRQF_DISABLED is not guaranteed on shared IRQs
lf1000-rtc lf1000-rtc: rtc core: registered lf1000-rtc as rtc0
LF1000 Real Time Clock driver.
i2c /dev entries driver
Software Watchdog Timer: 0.07 initialized. soft_noboot=0 soft_margin=60 sec (nowayout= 0)
setAudioRate: expected rate 32000Hz, actual: 32001Hz
*** MLC mlc_fb_addr=00000000 size=00000000 fb[0]=00000000 ***
lf1000-dpc driver
dpc: DPC not enabled, do config+enable
dpc: PWM clock rate is 9800000
input: LF1000 USB as /class/input/input0
input: Power Button as /class/input/input1
usb 1-1: new full speed USB device using lf1000-ohci and address 2
lf1000_power_probe.717 initial battery reading is :9575
input: LF1000 Keyboard as /class/input/input2
resource BUTTON_VOLUMEUP (16) port is undefined (-1)
resource BUTTON_VOLUMEUP (16) pin is undefined (-1)
resource BUTTON_VOLUMEDOWN (17) port is undefined (-1)
resource BUTTON_VOLUMEDOWN (17) pin is undefined (-1)
dm9000 Ethernet Driver, V1.31
Advanced Linux Sound Architecture Driver Version 1.0.20.
ALSA device list:
  No soundcards found.
TCP cubic registered
NET: Registered protocol family 17
lf1000-rtc lf1000-rtc: setting system clock to 1974-11-13 01:19:20 UTC (153537560)
Freeing init memory: 1608K
usb 1-1: device descriptor read/64, error -62
# Executing /init
sh: can't access tty; job control turned off
/ # usb 1-1: device descriptor read/64, error -62
usb 1-1: new full speed USB device using lf1000-ohci and address 3
usb 1-1: device descriptor read/64, error -62
usb 1-1: device descriptor read/64, error -62
usb 1-1: new full speed USB device using lf1000-ohci and address 4
usb 1-1: device not accepting address 4, error -62
usb 1-1: new full speed USB device using lf1000-ohci and address 5
usb 1-1: device not accepting address 5, error -62
hub 1-0:1.0: unable to enumerate USB device on port 1

/ # cat /proc/meminfo
MemTotal:         108540 kB
MemFree:          100960 kB
Buffers:               0 kB
Cached:             5016 kB
SwapCached:            0 kB
Active:              744 kB
Inactive:           4520 kB
Active(anon):        248 kB
Inactive(anon):        0 kB
Active(file):        496 kB
Inactive(file):     4520 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:           272 kB
Mapped:              444 kB
Slab:               1788 kB
SReclaimable:        456 kB
SUnreclaim:         1332 kB
PageTables:           48 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:       54268 kB
Committed_AS:        640 kB
VmallocTotal:     278528 kB
VmallocUsed:       18592 kB
VmallocChunk:     246780 kB
/ # ls
bin         init        linuxrc     proc        usr
dev         lib         lost+found  sbin
etc         libold      mnt         sys
/ # modprobe lf1000_mmc
lf1000_mmc: Unknown symbol mmc_request_done
lf1000_mmc: Unknown symbol mmc_remove_host
lf1000_mmc: Unknown symbol mmc_alloc_host
lf1000_mmc: Unknown symbol mmc_add_host
lf1000_mmc: Unknown symbol mmc_free_host
# XXX: checking for SDIO...
lf1000-sdio lf1000-sdio: response timeout
lf1000-sdio lf1000-sdio: response timeout
lf1000-sdio lf1000-sdio: response timeout
lf1000-sdio lf1000-sdio: response timeout
XXX: checking for SD...
XXX: SD...
mmc0: host does not support reading read-only switch. assuming write-enable.
mmc0: new SD card at address 0001
/ # modprobe mmc_block
mmcblk0: mmc0:0001 00000 1.89 GiB 
 mmcblk0: p1
/ # mount /dev/mmcblk0p1 /mnt
/ # ls /mnt
initrd~1.gz         zImage-46M-WORKING  zimage~1
initrd~1.gz         zImage.NAND-LX      zimage~1
initrd~1.gz         zimage~1            zimage~1
trash-~1            zimage~1            zimage~2
zImage              zimage~1
/ # 

Augen eGo OE-A732 TV-Out pads!

In addition to the JTAG pads, a couple of very promising pads for composite TV-Out! These pads link to Pollux BGA ball A2 (composite video...)



Augen eGo OE-A732 JTAG pads

Found JTAG pads on the Augen eGo (matching the Pollux BGA grid map).

On front:

On back:


Leapster Explorer: JumbotronLX!

The Leapster Explorer, a Linux-based children's handheld, is the follow-on product to the Didj. The Explorer runs the same ARM9-based SoC as its predecessor - one of our first tasks would be to uncover the Explorer's hidden TV-out mechanism.

I managed to overvolt my first Explorer by sending 5v into the USB host pins just days after I bought it. So, I purchased a second unit and dedicated the dead unit to 'science'. After desoldering the mainboard, I was able to trace from BGA grid A2 (Video) to the test pad TP30 '-Right'.


On my second Explorer, I soldered a short length of wire to TP30 and another to ground (cart socket), connected the ends to a composite connector, and modded the case.


I then used a 75 Ohm resistor as a filter - a simplified variant of the filter originally used in the Didj TV Out hack (no capacitors needed) - hooked up the oscilloscope, and got a good video waveform:


And a decent picture on my little test monitor.


The GBA emulator we recently ported works fine on the TV too - that first picture at the top of this post is from Castlevania...

Updated TV-out steps covering Didj and Leapster Explorer are on our wiki (full mainboard scans too!)

Thanks and greetz to everyone on #Didj (!