1 (edited by Dioptimizer 2012-04-20 13:51:09)

Topic: Debrick Routers with AR724x processors Using JTAG

Hello.

After analyzing a lot of routers (with including the EJTAG port) with processor AR724x  I can confirm of some of the pins used for de-bricking.
Very often meet routers that do not have labels with marking the start numbering pins of the processor.
To help You find the right pins, I wrote this illustration:

         128                97
           |                 |
      Lock-+-----------------+-96
           |                 |
           |       /\        |
DDR Chip - |     /----\      | - SPI (or NAND) Flash Chip
           |   /        \    |
           |     AR724x      |
           |                 |
        32-+-----------------+-65
           |                 |
          33                64 
                    |
                 Ethernet

AR724x CPUs:
EJTAG v3.1 pinout:

80pin  | 81pin  | 82pin | 84pin  | 85pin | 93pin
nTRST |  TDI  |  TDO  |  TMS  |  TCK  | RST ([s]nSRST[/s])

UART pinout:

 86pin | 87pin 
   Rx  |  Tx

If on PCB board of the router no place to EJTAG, then it is usually nTRST, TDI, TDO, TMS, TCK pins is used as a GPIOs pins.
But RST ([s]nSRST[/s]) pin is always connected to the VCC line (usually via a resistor) and is also a GPIO-pin.
Unlike nSRST which resets the CPU but JTAG is still active.
RST - also disables the JTAG, ie full chip reset (same as off/on the router).

On processors AR7241 and AR7242 (Critical for the routers with SPI Flash Memory) was changed the location of the CS# for Flash Chip (compared with an AR7240, where CS#-pin = 75-pin) and designated as a 80-pin = CS# - i.e. on one pin is located nTRST, CS# and GPIO.

When using the EJTAG on the router, usually nTRST (negative TAP Reset) is connected to VCC line – this way enabled TAP controller. Simply Wiggler JTAG cable used nTRST always pulled to the VCC for logical "1" (after the initialization of the cable) - it is usually necessary to confirm the MIPS EJTAG specification. As You can understand it is critical for SPI flash-chip that needs CS#.
More information about the EJTAG specification can be found at this link.

In practical use was discovered that the router MR3220v1.2 (AR7241) is still possible to use and JTAG interface and the SPI Flash Chip via JTAG interface as follows:

After pre-connecting to the router Simply DLC5 JTAG cable (this cable is only used: TDI, TDO, TMS, TCK pins) I made a manual nTRST switch, by soldering the Button between the CS# and VCC line (between this lines need to use resistor 10…50 ohms).

1. Turn-off the router
2. Connect the JTAG cable to Router and PC
3. Press and hold the button (manual nTRST)
4. Turn-on the router (wait until 2 .... 3 sec)
5. Depress the button (manual nTRST) - in this case the router or the AR7241 processor will be in TAP mode
6. After that we need use the program for JTAG and we have access to the flash chip.

Links:
http://www.linux-mips.org/wiki/JTAG
http://infodepot.wikia.com/wiki/TJTAG
http://www.wehavemorefun.de/fritzbox/index.php/EJTAG

Re: Debrick Routers with AR724x processors Using JTAG

Why o0n earth don't you use the wiki to document stuff?

3 (edited by Dioptimizer 2012-04-20 14:53:37)

Re: Debrick Routers with AR724x processors Using JTAG

Configuration (taget) file ar724x.cfg for OpenOCD:

# Atheros AR724x MIPS 24Kc SoC.
# tested on AP99 refererence board
#
# this settings are taken from source of u-boot for this board
# (for PLL) file:    u-boot/board/ar7240/common/lowlevel_init.S
# (for DDR) file:    u-boot/cpu/mips/ar7240/meminit.c
#      with file:    u-boot/include/configs/ap99.h

adapter_nsrst_delay 100
jtag_ntrst_delay 100

reset_config trst_only separate            ;# or use only "reset_config none"

set CHIPNAME ar724x

jtag newtap $CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id 1

set TARGETNAME $CHIPNAME.cpu
target create $TARGETNAME mips_m4k -endian big -chain-position $TARGETNAME

$TARGETNAME configure -event reset-init {
    #reset Watchdog Timer
    mww 0xb8060008 3            ;# rst watchdog timer control        <
    mww 0xb806000c 0x12c        ;# rst watchdog timer (resets SoC)    >
    sleep 10
    halt
    wait_halt

    #setup PLL to lowest(default) common denominator 400/400/200 setting
    mww 0xb8050000 0x00090828        ;# clr pll mask (rst: 02090828)
    mww 0xb8050000 0x00050828        ;# CPU:400 DDR:400 AHB:200
    mww 0xb8050000 0x00040828        ;# clr pll bypass

    #next command will reset for PLL changes to take effect 
    mww 0xb8050008 2            ;# set reset_switch
    mww 0xb8050008 3            ;# set clock_switch (resets SoC)
    sleep 10
    halt
    wait_halt

    #complete pll initialization
    mww 0xb8050008 0            ;# set reset_switch bit & clock_switch bit
    
    # Setup DDR config and flash mapping
    mww 0xb8000000 0xc7bc8cd0        ;# DDR cfg cdl val (rst: 77be8cd0)
    mww 0xb8000004 0x9dd0e6a8        ;# DDR cfg2 cdl val (rst: 99d10628)

    mww 0xb8000010 8            ;# force precharge all banks
    mww 0xb8000008 0x133            ;# DDR mode value init
    mww 0xb8000010 1            ;# force EMRS update cycle
    mww 0xb800000c 0            ;# clr ext. mode register

    mww 0xb8000010 2            ;# force auto refresh all banks
    mww 0xb8000010 8            ;# force precharge all banks
    mww 0xb8000008 0x33            ;# set DDR mode value CAS=3
    mww 0xb8000010 1            ;# force EMRS update cycle
    mww 0xb8000014 0x4f10        ;# DDR refresh value
    mww 0xb8000018 0xff            ;# DDR Read Data This Cycle value (16bit: 0xffff)
    mww 0xb800001c 2            ;# delay added to the DQS0 line (normal = 8)
    mww 0xb8000020 2            ;# delay added to the DQS1 line (normal = 9)
    mww 0xb8000024 0
    mww 0xb8000028 0
}

# setup working area somewhere in RAM
$TARGETNAME configure -work-area-phys 0xa0600000 -work-area-size 0x20000

# serial SPI capable flash
# flash bank <driver> <base> <size> <chip_width> <bus_width>

OpenOCD log when connected board:

D:\Free\OpenOCD\0.5.0>openocd-0.5.0.exe -f interface\parport.cfg -f target\ar724x.cfg
Open On-Chip Debugger 0.5.0 (2012-04-06-14:30)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.berlios.de/doc/doxygen/bugs.html
Warn : Adapter driver 'parport' did not declare which transports it allows; assu
ming legacy JTAG-only
Info : only one transport option; autoselect 'jtag'
parport port = 0x378
6000 kHz
adapter_nsrst_delay: 100
jtag_ntrst_delay: 100
none separate
131072
Info : clock speed 500 kHz
Info : JTAG tap: ar724x.cpu tap/device found: 0x00000001 (mfg: 0x000, part: 0x0
000, ver: 0x0)
Info : accepting 'telnet' connection from 4444

My telnet log:

Open On-Chip Debugger
> reset
JTAG tap: ar724x.cpu tap/device found: 0x00000001 (mfg: 0x000, part: 0x0000, ver: 0x0)
> halt
target state: halted
target halted in MIPS32 mode due to debug-request, pc: 0xbfc03860
> reset
JTAG tap: ar724x.cpu tap/device found: 0x00000001 (mfg: 0x000, part: 0x0000, ver: 0x0)
target state: halted
target halted in MIPS32 mode due to debug-request, pc: 0xbfc03860
> mww 0xb8060008 3
> mww 0xb806000c 0x12c
in procedure 'mww'
> halt
target state: halted
target halted in MIPS32 mode due to debug-request, pc: 0xbfc03860
> mww 0xb8050000 0x00090828
> mww 0xb8050000 0x00050828
> mww 0xb8050000 0x00040828
> mww 0xb8050008 2
> mww 0xb8050008 3
in procedure 'mww'
> halt
target state: halted
target halted in MIPS32 mode due to debug-request, pc: 0xbfc03860
> reset init
JTAG tap: ar724x.cpu tap/device found: 0x00000001 (mfg: 0x000, part: 0x0000, ver: 0x0)
target state: halted
target halted in MIPS32 mode due to debug-request, pc: 0xbfc03860
> load_image backup_fullflash.bin 0x81000000
4194304 bytes written at address 0x81000000
downloaded 4194304 bytes in 434.899994s (9.418 KiB/s)
> load_image 8Muboot_RAM_version.bin 0x80000000
262144 bytes written at address 0x80000000
downloaded 262144 bytes in 21.150000s (12.104 KiB/s)
> resume 0x80000000

If you see error "in procedure 'mww'" - its bug OpenOCD.
reset init - for my build of OpenOCD (with bugs), I changed init script so that it begins with "# complete pll initialization".


Parallel you should use UART and you will see:

U-Boot 1.3.0-TT-0.1.0 (Nov 29 2011 - 19:25:10)@TTHR

              IN DEBUG MODE

AP99 (ar7241 - Virian) U-boot
#### TAP VALUE 1 = 0x2, 2 = 0x2 [0x0: 0x0]
CPU_FREQ=400##DDR_FREQ=400##AHB_FREQ=200
DRAM:  32 MB
uboot_end=[0x80030320]###len=[0x30320]Top of RAM usable for U-Boot at: 82000000
Reserving 192k for U-Boot at: 81fcc000
Reserving 192k for malloc() at: 81f9c000
Reserving 44 Bytes for Board Info at: 81f9bfd4
Reserving 36 Bytes for Global Data at: 81f9bfb0
Reserving 128k for boot params() at: 81f7bfb0
Stack Pointer at: 81f7bf98
Now running in RAM - U-Boot at: 81fcc000
Flash:  8 MB
Using default environment


Warnning Board Uncolabrated!!
In:    serial
Out:   serial
Err:   serial
Net:   ag7240_enet_initialize...
No valid address in Flash. Using fixed address
No valid address in Flash. Using fixed address
Virian MDC CFG Value ==> 4
: cfg1 0xf cfg2 0x7014
eth0: 40:16:9f:ab:e0:82
eth0 up
Virian MDC CFG Value ==> 4
: cfg1 0xf cfg2 0x7214
eth1: 40:16:9f:ab:e0:82
ATHRS26: resetting s26
ATHRS26: s26 reset done
eth1 up
eth0, eth1
### main_loop entered: bootdelay=1

### main_loop: bootcmd="bootm 0x9f020000"
Autobooting in 1 seconds press tt to abort
AR7241#

And last commands in OpenOCD telnet:

> jtag_reset 1 0
> shutdown

jtag_reset 1 0      <= use this command, if you also use nTRST pin on JTAG cable. This command will disable nTRST line on JTAG adaptor.

Uboot for AP99 from tthrx      <= thx bro
https://forum.openwrt.org/viewtopic.php?id=33205


P.S.
Bootloader for the other boards need change so that it was loaded from SDRAM.

Or if someone wants to: you can make a universal u-boot - before applying specific configuration (while uboot is loading) of ap99, pb90, pb93, etc. theoretically, we could choose its configuration via the console by typing command. This is possible because UART (GPIO 9 and 10) - common for this CPUs.

4 (edited by Dioptimizer 2012-06-29 01:06:47)

Re: Debrick Routers with AR724x processors Using JTAG

Last wiki version

Re: Debrick Routers with AR724x processors Using JTAG

Alternative universal bootloader over JTAG (with flash size detection) - myloram.
Also there is another varian for AR71xx CPU's.

Re: Debrick Routers with AR724x processors Using JTAG

I have a totally bricked D-link DIR-615 H/W E3 with AR7240 CPU and MX25L3206  flash.

Already soldered a serial and jtag connector to the board, and I have also made a parallel Xilinx DLC5 cable.
Followed DIOPTIMIZER instructions, traced nTRST-TDI-TDO-TTMS-TCK lines from JTAG connector to CPU and discovered that some of them were interrupted by a missing resistors on board.....soldered jumpers instead of them.
Also created a manual reset button between +VCC (pin 14 on JTAG) and nTRST (used a 100 ohm resistor)
Connected a TTL to RS232 converter to serial (TX,RX,GND)....used Windows Hyperterminal , but getting nothing.

Should I be able to received something from serial port even if router's bootloader is probably dead ??

So far have not found any JTAG program , which would support AR7240 CPU and MX25L3206 flash !!
Does  the mentioned MYLORAM or MYLOADER or OPENOCD has support for these chips ?
Thanks

Re: Debrick Routers with AR724x processors Using JTAG

Sorry, but I'm going to have to resurrect the dead on this one.  I tried the above process on a WZR-HP-G300NH2 router running the AR7242 proc, but I haven't had much luck.  I tried variations of this as well.  Here's what I've tried in hopes that someone can help me figure out why this isn't working right.

Router: WZR-HP-G300NH2
Proc: AR7242-AH1A
JTAG Unit: USB JTAG NT
Originally sought help at: http://www.usbjtag.com/vbforum/showthre … mp;p=55639

try{
//On the back of the board, there's a blank space for a resistor (R309) which has one pad directly connected to pin 80 and the other pad is connected to ground.  I soldered a wire to the pad attached to pin 80.  I soldered the other end of the wire to a 35.7 Ohm resistor and the other end of the 35 Ohm resistor to a PBNO switch and the other end of the switch to the VCC on the serial port.  (Pin 1 - 3.3v)
}

catch:{
//USB JTAG NT reported "Debug Off" after following the steps to keep pin 80 hot while booting the unit and then releasing the switch after 2 seconds.
}



try{
//I removed the resistor and tried again to see if putting the full 3.3V through would fix the issue.  (I was reading 2.59V on my voltmeter with the resistor in.)
}

catch{
//That didn't work. It still said "Debug Off" on USB JTAG NT.  (Keep in mind that I know my USB JTAG NT is working properly and I did use it on other units successfully.  USBBDM (The guy who created USB JTAG NT) told me to use the settings for WRT160NL and that's what I've been using for this unit.  He referred me to this thread to try it out as well.
}



try{
//I tried hooking pin 80 directly to VCC and not releasing it.
}

catch{
//It still said "Debug Off."
}



try{
//I tried connecting pin 80 to the JTAG header's pin 1 (nTRST pin that's disconnected from the board - no circuitry connects to it) as USB JTAG NT keeps that line hot.
}

catch{
//USB JTAG NT's software reports "Debug Off."
}



I have yet to try out using pin 93 as the VCC source, but the only way I'd see that working is if it pulls enough voltage away from pin 93 that it goes low and pin 80 goes high from powering both pins, but my best guess is that they both would go low as you'd be splitting the power source at an original 3.3v.

Does anyone have any other ideas I can try with this unit?  Has anyone ever fondled it's JTAG port before?  lol

8 (edited by Dioptimizer 2013-07-13 00:20:49)

Re: Debrick Routers with AR724x processors Using JTAG

LightworkerNaven
What is your target to use JTAG on the device?

If you want to restore the flash memory, can easily connect to the flash memory (no Desoldering) via SPI programmator, and the processor to translate in RST mode (so all GPIO's will not be active - low state).

All my experiments were without datasheet, even now there is no way to find the datasheet for this processor (AR724x).
I even say more, I'm not sure that "nTRST" exists at all on processors ar7241/ar7242 (unlike ar7240).
The fact is that when we connect the power to the 80pin - it disables the flash memory on the device (if it is connected to this 80-pin=CS0-pin on flashchip) - the processor just not initialized and enabling the JTAG or may switches to Test/Debug Mode.

What does this "Debug Off."?
Do you have an extended response from the software?
What is the IDentifier of the processor is waiting for your software, if it is waiting for it at all?
Under that link confuses me a configuration file that contains the option availability of DMA in the JTAG - this is not true.
All operations with a processor only PrAcc mode.
Also option IRLength which should be "5" (have you seen the config. file for OpenOCD?)

jtag newtap $CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id 1

Sorry for my English is incredibly horrible.

Re: Debrick Routers with AR724x processors Using JTAG

USB JTAG NT is a proprietary program that I bought to JTAG my stuff with since it seems to be the most comprehensive of the ones I saw while researching.  It's easy to use and comes with a GUI.  The "Debug Off" bit is part of that program and also the DMA bit is part of what it reads from it's config.  DMA just means dynamic memory address and because it isn't starting at 0x0 usually, it's dynamic in terms of it's placement in the chip.  That's my take on why he added that.

As for using the JTAG port on the WZR-HP-G300NH2, I figured out how to make it work properly using this tutorial for the pinout and following the traces on the board to discover that several resistors were missing to interrupt the JTAG.  My findings can be found in this post which I'll keep updated until I'm done with the JTAG process.

http://www.usbjtag.com/vbforum/showthre … ;page=2#21

By the way, thanks for the IR Length code.  I'll go and check into converting the config files you posted and modifying them to work with USB JTAG NT with my unit.

Re: Debrick Routers with AR724x processors Using JTAG

Is there anybody who connected to JTAG on D-Link DIR-615-E4 (AR7240 chip) successfully?

I'm soldered jumpers instead of missing resistors on the board, so all JTAG ping connected to AR7240 chip correctly (in accordance to info at first post).
I'm connected to the board via J-Link clone using openocd-0.7, but not success:

>openocd-0.7.0.exe -f interface\jlink.cfg -f target\ar71xx.cfg -c "adapter_khz 10"
Open On-Chip Debugger 0.7.0 (2013-05-05-10:41)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'jtag'
adapter_nsrst_delay: 100
jtag_ntrst_delay: 100
trst_and_srst separate srst_gates_jtag trst_push_pull srst_open_drain connect_deassert_srst
131072
adapter speed: 10 kHz
Info : J-Link initialization started / target CPU reset initiated
Info : J-Link compiled Dec 03 2007 17:15:31 ARM Rev.5
Info : J-Link caps 0xdffbf
Info : J-Link hw version 53000
Info : J-Link hw type J-Link
Info : J-Link max mem block 9992
Info : J-Link configuration
Info : USB-Address: 0xff
Info : Kickstart power on JTAG-pin 19: 0xffffffff
Info : Vref = 2.517 TCK = 1 TDI = 0 TDO = 0 TMS = 0 SRST = 0 TRST = 0
Info : J-Link JTAG Interface ready
Info : clock speed 10 kHz
Error: JTAG scan chain interrogation failed: all zeroes
Error: Check JTAG interface, timings, target power, etc.
Error: Trying to use configured scan chain anyway...
Error: ar71xx.cpu: IR capture error; saw 0x00 not 0x01
Warn : Bypassing JTAG setup events due to errors

Re: Debrick Routers with AR724x processors Using JTAG

I am doing some openocd tests over a wr841nd 7.2, mostly cache code related. Now this board is working fine
for me. The board is halted using the ntrst line from my ftdi hs adapter (self made). After deasserting the RST line there is around 15 to 20 ms time left to halt the core. Openocd at 500khz takes about 3 or 4ms to halt it. Setting adapter_khz below 50khz fails.
With additional hardware the core can be halted by blocking the clock at pin 94, the tap seems to work without clocking.
For memory dump from spi flash mips32 scan_delay must be set to 3600 or higher and the transfer speed is around 75Kbytes/s at 15000khz scan rate. For memory loads to ram scan_delay can be set to 0 and the transfer speed is over 600Kbytes/s (works with fast data transfer).
In case of fail in queued mode probably openocd refuses to work because pracc access don't starts at pracc text. The only option is a reset or if you want call the jtt utility ( in the config).
Use mips32 scan_delay 2000000 to jump back to legacy mode.
Use only the ftdi adapter driver. DO NOT USE ft2232!!!! if you have ftdi based adapter of course.
Wiggler works a bit faster in queued mode but not much, better let it in legacy mode (by default for every adapter).
Good luck an thanks for the code, my English is not better.

#################  config ######################

# Atheros AR724x MIPS 24Kc SoC.
# tested on AP99 refererence board
#
# this settings are taken from source of u-boot for this board
# (for PLL) file:    u-boot/board/ar7240/common/lowlevel_init.S
# (for DDR) file:    u-boot/cpu/mips/ar7240/meminit.c
#      with file:    u-boot/include/configs/ap99.h

# preliminary config based on https://forum.openwrt.org/viewtopic.php?id=34993
# tested on an ar7241-ah1a based board

if { [info exists CHIPNAME] } {
   set _CHIPNAME $CHIPNAME
} else {
   set _CHIPNAME AR7241
}

if { [info exists ENDIAN] } {
   set _ENDIAN $ENDIAN
} else {
   set _ENDIAN big
}

if { [info exists CPUTAPID] } {
   set _CPUTAPID $CPUTAPID
} else {
   set _CPUTAPID 0x00000001
}

jtag_ntrst_assert_width 200
jtag_ntrst_delay 1

reset_config trst_only

jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x1 -irmask 0x1f -expected-id $_CPUTAPID

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME mips_m4k -endian $_ENDIAN -chain-position $_TARGETNAME


# setup working area somewhere in RAM
$_TARGETNAME configure -work-area-phys 0x80600000 -work-area-size 0x20000


$_TARGETNAME configure -event reset-init {
    global _TARGETNAME
    mips32 scan_delay 2000000        ;# do it in legacy mode

    mww 0xb8060008 3            ;# rst watchdog timer control
    irscan $_TARGETNAME 0xc            ;# ejtagboot indication, internal reset will be triggered

    # catch error, mww will fail after reset
    catch { mww 0xb806000c 0x12c }        ;# rst watchdog timer (resets SoC)

    echo "watchdog settings done"
    sleep 200
    halt

    mww 0xb8050000 0x00090828        ;# clr pll mask (rst: 02090828)
    mww 0xb8050000 0x00050828        ;# CPU:400 DDR:400 AHB:200
    mww 0xb8050000 0x00040828        ;# clr pll bypass

    #next command will reset for PLL changes to take effect

    mww 0xb8050008 2            ;# set reset_switch
    irscan $_TARGETNAME 0xc            ;# ejtagboot indication, internal reset will be triggered

    # catch error, really not needed in this case, in legacy mode  it reads a second pass through pracc text (like a normal exit)
    catch { mww 0xb8050008 3 }        ;# set clock_switch (resets SoC)

    echo "pll settings done"
    sleep 200
    halt

    mww 0xb8050008 0        ;# set reset_switch bit & clock_switch bit
   
    # Setup DDR config and flash mapping

    mww 0xb8000000 0xc7bc8cd0    ;# DDR cfg cdl val (rst: 77be8cd0)
    mww 0xb8000004 0x9dd0e6a8    ;# DDR cfg2 cdl val (rst: 99d10628)

    mww 0xb8000010 8        ;# force precharge all banks
    mww 0xb8000008 0x133        ;# DDR mode value init
    mww 0xb8000010 1        ;# force EMRS update cycle
    mww 0xb800000c 0        ;# clr ext. mode register

    mww 0xb8000010 2        ;# force auto refresh all banks
    mww 0xb8000010 8        ;# force precharge all banks
    mww 0xb8000008 0x33        ;# set DDR mode value CAS=3
    mww 0xb8000010 1        ;# force EMRS update cycle
    mww 0xb8000014 0x4f10        ;# DDR refresh value
    mww 0xb8000018 0xff        ;# DDR Read Data This Cycle value (16bit: 0xffff)
    mww 0xb800001c 2        ;# delay added to the DQS0 line (normal = 8)
    mww 0xb8000020 2        ;# delay added to the DQS1 line (normal = 9)
    mww 0xb8000024 0
    mww 0xb8000028 0

    irscan $_TARGETNAME 0xd        ;# normalboot

    echo ""
    echo "Targed initialized uncached"
}



# serial SPI capable flash
# flash bank <driver> <base> <size> <chip_width> <bus_width>

# Make a jump to text (0xff200200) utility
proc jtt {} {
    poll off
    sleep 50
    global _TARGETNAME
    irscan $_TARGETNAME 0x9            ;# select data register
    drscan $_TARGETNAME 32 0xbc80080    ;# Jump code
    irscan $_TARGETNAME 0xa            ;# select control register
    drscan $_TARGETNAME 32 0x8000c000    ;# finish processor access, go to next
    sleep 50
    irscan $_TARGETNAME 0x9
    drscan $_TARGETNAME 32 0        ;# Nop code, in delay slot of the jump
    irscan $_TARGETNAME 0xa
    drscan $_TARGETNAME 32 0x8000c000
    poll on
}
####################### end config #############################

12 (edited by Dioptimizer 2013-08-14 15:17:32)

Re: Debrick Routers with AR724x processors Using JTAG

sarroyo wrote:

...In case of fail in queued mode probably openocd refuses to work because pracc access don't starts at pracc text. The only option is a reset or if you want call the jtt utility ( in the config)....

Another my config file

OEM COMPEX WPE72(Atheros AR724x) config file (without resets SoC):

init-ar7240.mac wrote:

; macro file for AR7200 boards (32/64 MB ram)
; OCD Commander settings:
;     Target Processor: MIPS, EJTAG 2.5, 32 bit
;     Connection      : LPT1
;     OCD Device      : Wiggler
;     OCD Speed       : 380 KHz

reset
mipsendian big


; WAR for the bug#55574: Set the CKE (bit 7 in DDR_CONFIG2 register)
; to low initially
word 0xB8000004 = 0x99D10628


; set PLL
word 0xb8050000 = 0x00040828


; update PLL
word 0xb8050008 = 0x1
delay 10

word 0xb8050008 = 0x0

; disable flash remap
word 0xbf000004 = 0x43


; DDR

word 0xb8000000 = 0xC7BC8CD0
word 0xB8000004 = 0x9DD0E6A8
word 0xB8000010 = 0x00000008
word 0xB8000008 = 0x00000133
delay 10

word 0xB8000010 = 0x00000001
word 0xB800000C = 0x00000000
word 0xB8000010 = 0x00000002
word 0xB8000010 = 0x00000008
word 0xB8000008 = 0x00000033
word 0xB8000010 = 0x00000001

word 0xB8000014 = 0x00004F10
word 0xB8000018 = 0x000000FF

word 0xB800001C = 0x00000007
word 0xB8000020 = 0x00000007

;
; UART Test
;

word 0xB8040028 = 0x000480FA

word 0xB802000C = 0x00000083
word 0xB8020000 = 0x0000006D
word 0xB8020004 = 0x00000000
word 0xB802000C = 0x00000003
word 0xB8020008 = 0x00000001

word 0xB8020000 = 0x00000030
word 0xB8020000 = 0x00000031
word 0xB8020000 = 0x00000032
word 0xB8020000 = 0x00000033
word 0xB8020000 = 0x00000034
word 0xB8020000 = 0x00000035
word 0xB8020000 = 0x00000036
word 0xB8020000 = 0x00000037
word 0xB8020000 = 0x00000038
word 0xB8020000 = 0x00000039
word 0xB8020000 = 0x0000000D
word 0xB8020000 = 0x0000000A

; load file
delay 500
download myloram.srec

delay 100
go

http://wiki.openwrt.org/doc/techref/boo … er#myloram

sarroyo
If you can, please, put here your TEST with this(COMPEX) configuration file (also with a universal boot loader myloram) and place your results here.
Thanks anyway.

Re: Debrick Routers with AR724x processors Using JTAG

The new configuration for init works much better and is much simpler. Scan_delay can be set to 0 for memory dumps and  at 15000Khz in queued mode works up to 114kb/s. Contrary for memory writes to ram i need to add now a little delay of about 100, but still works over 600Kb/s.
Cache modes can be changed in config register and works without any other additional configuration, fine.
Seems the flash is working a bit faster.
The bad news is that myloram does not work me. Ping does not work at all  and i end making some stupidity and bricking my router. Here is part of the  log from the serial console:

Main Menu

1 - Load Firmware
2 - Load Program
3 - BIOS Setup
4 - Fdisk Utility
5 - Update Flash (Binary Mode)
6 - Update Firmware (Image Mode)
7 - Reboot System
8 - Memory Test

Please select : 3

BIOS Setup

1 - Device ID Setup
2 - Flash Setup
3 - DRAM Setup
4 - Boot Mode Setup
5 - TFTP Server Setup
6 - Ethernet Address Setup
7 - Load Default
8 - Ethernet Interface Setup

Please select : 1

Device ID Setup

Vendor ID (11f6) :

evice ID (0672) :
Subvendor ID (11f6) : 
Subdevice ID (0672) :
Revision (00000000) :
Update System Paramters ............. Done

BIOS Setup

1 - Device ID Setup
2 - Flash Setup
3 - DRAM Setup
4 - Boot Mode Setup
5 - TFTP Server Setup
6 - Ethernet Address Setup
7 - Load Default
8 - Ethernet Interface Setup

Please select : 3

DRAM Setup

DRAM Size (02000000) :
Update System Paramters ............. Done

BIOS Setup

1 - Device ID Setup
2 - Flash Setup
3 - DRAM Setup
4 - Boot Mode Setup
5 - TFTP Server Setup
6 - Ethernet Address Setup
7 - Load Default
8 - Ethernet Interface Setup

Please select : 4

Boot Mode Setup

1 - Load Firmware
2 - Load Program (HEX)
3 - Load Program (BIN)
4 - Load Program (ELF)
5 - Update Firmware
6 - Main Menu

Please Select 1

Update System Paramters ............. Done

BIOS Setup

1 - Device ID Setup
2 - Flash Setup
3 - DRAM Setup
4 - Boot Mode Setup
5 - TFTP Server Setup
6 - Ethernet Address Setup
7 - Load Default
8 - Ethernet Interface Setup

Please select : Exit

Main Menu

1 - Load Firmware
2 - Load Program
3 - BIOS Setup
4 - Fdisk Utility
5 - Update Flash (Binary Mode)
6 - Update Firmware (Image Mode)
7 - Reboot System
8 - Memory Test

Please select : 7

Reboot System
ÿ

U-Boot 1.1.4 (Sep  3 2010 - 12:35:51)

AP99 (ar7241 - Virian) U-boot
DRAM:
sri
ar7240_ddr_initial_config(133): virian ddr1 init
#### TAP VALUE 1 = 0xf, 2 = 0x10 [0x0: 0x1f]
32 MB
id read 0x100000ff
sector count = 64
Flash:  4 MB
Using default environment

In:    serial
Out:   serial
Err:   serial
Net:   ag7240_enet_initialize...
No valid address in Flash. Using fixed address
No valid address in Flash. Using fixed address
Virian MDC CFG Value ==> 4
: cfg1 0xf cfg2 0x7014
eth0: 00:03:7f:09:0b:ad
eth0 up
Virian MDC CFG Value ==> 4
: cfg1 0xf cfg2 0x7214
eth1: 00:03:7f:09:0b:ad
ATHRS26: resetting s26
ATHRS26: s26 reset done
eth1 up
eth0, eth1
Autobooting in 1 seconds
## Booting image at 9f020000 ...
   Uncompressing Kernel Image ... OK

Starting kernel ...



OpenWrt kernel loader for AR7XXX/AR9XXX
Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
Decompressing kernel...
failed,
data error!

System halted!

#################################### end console log

Whit verify_image i found this diffs:
checksum mismatch - attempting binary compare
diff 0 address 0xbfc2f800. Was 0x20 instead of 0xea
diff 1 address 0xbfc2f801. Was 0x02 instead of 0x3b
diff 2 address 0xbfc2f802. Was 0x11 instead of 0x1b
diff 3 address 0xbfc2f803. Was 0x07 instead of 0x8c
diff 4 address 0xbfc2f804. Was 0x00 instead of 0x7d
diff 5 address 0xbfc2f805. Was 0x00 instead of 0x44
diff 6 address 0xbfc2f806. Was 0x00 instead of 0x8a
diff 7 address 0xbfc2f807. Was 0x00 instead of 0x88
diff 8 address 0xbfc2f808. Was 0x00 instead of 0xe6
diff 9 address 0xbfc2f809. Was 0x00 instead of 0x56
diff 10 address 0xbfc2f80a. Was 0x00 instead of 0xa2
diff 11 address 0xbfc2f80b. Was 0x00 instead of 0x47
diff 12 address 0xbfc2f80c. Was 0x00 instead of 0xf5
diff 13 address 0xbfc2f80d. Was 0x00 instead of 0x39
diff 14 address 0xbfc2f80e. Was 0x00 instead of 0x31
diff 15 address 0xbfc2f80f. Was 0x00 instead of 0x52
diff 16 address 0xbfc2f810. Was 0x11 instead of 0x35
diff 17 address 0xbfc2f811. Was 0xf6 instead of 0xaa
diff 18 address 0xbfc2f812. Was 0x06 instead of 0xe4
diff 19 address 0xbfc2f813. Was 0x72 instead of 0x41
diff 20 address 0xbfc2f814. Was 0x11 instead of 0xf6
diff 21 address 0xbfc2f815. Was 0xf6 instead of 0xad
diff 22 address 0xbfc2f816. Was 0x06 instead of 0x50
diff 23 address 0xbfc2f817. Was 0x72 instead of 0xf8
diff 24 address 0xbfc2f818. Was 0x00 instead of 0x7d
diff 25 address 0xbfc2f819. Was 0x00 instead of 0x08
diff 26 address 0xbfc2f81a. Was 0x00 instead of 0xff
diff 27 address 0xbfc2f81b. Was 0x00 instead of 0x1a
diff 28 address 0xbfc2f81c. Was 0x00 instead of 0x86
diff 29 address 0xbfc2f81d. Was 0x02 instead of 0xe5
diff 30 address 0xbfc2f81e. Was 0x00 instead of 0x71
diff 31 address 0xbfc2f81f. Was 0x00 instead of 0xc8
diff 32 address 0xbfc2f820. Was 0x00 instead of 0x3e
diff 33 address 0xbfc2f821. Was 0x00 instead of 0x30
diff 34 address 0xbfc2f822. Was 0x00 instead of 0x34
diff 35 address 0xbfc2f823. Was 0x02 instead of 0xbe
diff 36 address 0xbfc2f824. Was 0xc0 instead of 0xb5
diff 37 address 0xbfc2f825. Was 0xa8 instead of 0x0c
diff 38 address 0xbfc2f826. Was 0xa8 instead of 0x72
diff 39 address 0xbfc2f827. Was 0x01 instead of 0x82
diff 40 address 0xbfc2f828. Was 0x80 instead of 0x13
diff 41 address 0xbfc2f829. Was 0x00 instead of 0xa7
diff 42 address 0xbfc2f82a. Was 0x20 instead of 0x3a
diff 43 address 0xbfc2f82b. Was 0x00 instead of 0x57
diff 44 address 0xbfc2f82c. Was 0x00 instead of 0xe4
diff 45 address 0xbfc2f82d. Was 0x40 instead of 0x6a
diff 46 address 0xbfc2f82e. Was 0x00 instead of 0xa9
diff 47 address 0xbfc2f82f. Was 0x00 instead of 0x0a
diff 48 address 0xbfc2f830. Was 0x02 instead of 0x67
diff 49 address 0xbfc2f831. Was 0x00 instead of 0xf5
diff 50 address 0xbfc2f832. Was 0x00 instead of 0x86
diff 51 address 0xbfc2f833. Was 0x00 instead of 0x28
diff 52 address 0xbfc2f834. Was 0x01 instead of 0x16
diff 53 address 0xbfc2f835. Was 0x00 instead of 0x75
diff 54 address 0xbfc2f836. Was 0x00 instead of 0x4b
diff 55 address 0xbfc2f837. Was 0x00 instead of 0x3b
diff 56 address 0xbfc2f838. Was 0x10 instead of 0xf5
diff 57 address 0xbfc2f839. Was 0x43 instead of 0xa6
diff 58 address 0xbfc2f83a. Was 0x80 instead of 0xd2
diff 59 address 0xbfc2f83b. Was 0x12 instead of 0x2f
diff 60 address 0xbfc2f83c. Was 0x00 instead of 0x99
diff 61 address 0xbfc2f83d. Was 0x00 instead of 0x44
diff 62 address 0xbfc2f83e. Was 0x00 instead of 0x26
diff 63 address 0xbfc2f83f. Was 0x00 instead of 0xb5
diff 64 address 0xbfc2f840. Was 0x00 instead of 0xcb
diff 65 address 0xbfc2f841. Was 0x00 instead of 0x60
diff 66 address 0xbfc2f842. Was 0x00 instead of 0xc7
diff 67 address 0xbfc2f843. Was 0x00 instead of 0x70
diff 68 address 0xbfc2f844. Was 0x00 instead of 0x7b
diff 69 address 0xbfc2f845. Was 0x00 instead of 0xee
diff 70 address 0xbfc2f846. Was 0x00 instead of 0x26
diff 71 address 0xbfc2f847. Was 0x00 instead of 0x80
diff 72 address 0xbfc2f848. Was 0x00 instead of 0x09
diff 73 address 0xbfc2f849. Was 0x00 instead of 0xc3
diff 74 address 0xbfc2f84a. Was 0x00 instead of 0xba
diff 75 address 0xbfc2f84b. Was 0x00 instead of 0x54
diff 76 address 0xbfc2f84c. Was 0x00 instead of 0x03
diff 77 address 0xbfc2f84d. Was 0x00 instead of 0xa7
diff 78 address 0xbfc2f84e. Was 0x00 instead of 0xb6
diff 79 address 0xbfc2f84f. Was 0x00 instead of 0x59
diff 80 address 0xbfc2f850. Was 0x00 instead of 0x83
diff 81 address 0xbfc2f851. Was 0x00 instead of 0xa5
diff 82 address 0xbfc2f852. Was 0x00 instead of 0xed
diff 83 address 0xbfc2f853. Was 0x00 instead of 0x1e
No more differences found.

################################## end diffs

I tried to halt the bootlader to find  out a solution but no luck. So i end putting the flash code from u-boot in a file
added a main function, a Makefile, a linker script to load the code at 0xa0000000, solved all the dependencies, typedefs, etc.. and run the code in ram.
First to erase the sector at 0xbfc20000 ( i forgot to setup the stack pointer and the entry address for main() (not a 0xa0000000) ) and next another build to flash the bricked sector. Not easy but now is working again.

Thanks for the new config is much better.

Re: Debrick Routers with AR724x processors Using JTAG

Hi all,

i have connected Raspberry p B+ as jtag dongle to my wzr-hp-g300nh, tjtag can detect CPU/Flash chip/Debug CPU on; but i cannot read flash since tjtag frozen (still running) at "resuming processor...." or "halting processor..."

Someone can help me to read CFE or reflash CFE boot?

Thanks

Re: Debrick Routers with AR724x processors Using JTAG

While hacking on my TL-WR1043ND (see also the "U-Boot mod for routers with AR9331/AR9344" thread https://forum.openwrt.org/viewtopic.php … 8#p297298) I accidentally wrote a bad version to the flash and got annoyed that you can't easily debrick over JTAG (unless you can make the RAM initialization work and upload a RAM u-boot) and my SPI-programmer didn't seem to work for in-circuit programming (tried keeping the CPU in reset, didn't help).

Since I didn't want to unsolder the SPI I looked into adding the proper necessary flash programming support to OpenOCD and now have this (@500kHz JTAG clock, doesn't get much faster with higher clocks since with the FTDI2232 the effective speed is severly limited by the USB round-trip-time):

$ telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> flash write_image unlock /tmp/test.bin 0xbf040000 
auto unlock enabled
read_flash_id: 1840ef
Found flash device 'win w25q128' (ID 0x001840ef)
writing 256 bytes to flash page @0x00000000
writing 256 bytes to flash page @0x00000100
writing 256 bytes to flash page @0x00000200
writing 256 bytes to flash page @0x00000300
[...]
writing 256 bytes to flash page @0x0001e800
writing 256 bytes to flash page @0x0001e900
writing 256 bytes to flash page @0x0001ea00
writing 256 bytes to flash page @0x0001eb00
wrote 131072 bytes from file /tmp/u-boot_mod.20151021.tl-wr1043nd.bin in 1678.842163s (0.076 KiB/s)

Necessary openocd.cfg setting:

flash bank ath79 ath79 0xbf000000 0x01000000 0 0 $_TARGETNAME

diffstat:

 Makefile.am |    1 
 ath79.c     |  807 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers.c   |    2 
 spi.c       |    1 
 4 files changed, 811 insertions(+)

Patch:

diff -x minidriver_imp.h -x xscale_debug.inc -x startup_tcl.inc -x startup.tcl -x openocd -x Makefile.in -x Makefile -Nru openocd-0.9.0-vanilla/src/flash/nor/ath79.c openocd-0.9.0/src/flash/nor/ath79.c
--- openocd-0.9.0-vanilla/src/flash/nor/ath79.c    1970-01-01 01:00:00.000000000 +0100
+++ openocd-0.9.0/src/flash/nor/ath79.c    2015-10-24 19:08:21.814867892 +0200
@@ -0,0 +1,807 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Antonio Borneo <borneo.antonio@gmail.com>       *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+/* STM Serial Memory Interface (SMI) controller is a SPI bus controller
+ * specifically designed for SPI memories.
+ * Only SPI "mode 3" (CPOL=1 and CPHA=1) is supported.
+ * Two working modes are available:
+ * - SW mode: the SPI is controlled by SW. Any custom commands can be sent
+ *   on the bus.
+ * - HW mode: the SPI but is under SMI control. Memory content is directly
+ *   accessible in CPU memory space. CPU can read, write and execute memory
+ *   content. */
+
+/* ATTENTION:
+ * To have flash memory mapped in CPU memory space, the SMI controller
+ * have to be in "HW mode". This requires following constraints:
+ * 1) The command "reset init" have to initialize SMI controller and put
+ *    it in HW mode;
+ * 2) every command in this file have to return to prompt in HW mode. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include "spi.h"
+#include <jtag/jtag.h>
+#include <helper/time_support.h>
+#include <target/mips32.h>
+#include <target/mips32_pracc.h>
+
+#define ATH79_REG_FS     0
+#define ATH79_REG_CLOCK  4
+#define ATH79_REG_WRITE  8
+#define ATH79_REG_DATA  12
+
+#define AR7240_SPI_CS_DIS  0xf0000
+#define AR7240_SPI_CE_LOW  0x60000
+#define AR7240_SPI_CE_HIGH 0x60100
+
+#define SMI_READ_REG(a) (0)
+#define SMI_WRITE_REG(a, v) (0)
+
+#define READ_REG(a) (_READ_REG(a))
+#define _READ_REG(a)            \
+{                                    \
+    int __a;                        \
+    uint32_t __v;                    \
+                                    \
+    __a = target_read_u32(target, io_base + (a), &__v); \
+    if (__a != ERROR_OK)            \
+        return __a;                    \
+    return __v;                            \
+}
+
+#define WRITE_REG(a, v)            \
+{                                    \
+    int __r;                        \
+                                    \
+    __r = target_write_u32(target, io_base + (a), (v)); \
+    if (__r != ERROR_OK)            \
+        return __r;                    \
+}
+
+#if 0
+static uint32_t ath79_read_reg(struct target *target, uint32_t reg) {
+    uint32_t v = 0;
+    int err = target_read_u32(target, 0xbf000000 + reg, &v);
+    if (err != ERROR_OK) {
+        LOG_ERROR("target_read_u32 failed");
+    }
+    return v;
+}
+
+static void ath79_write_reg(struct target *target, uint32_t reg, uint32_t value) {
+    int err = target_write_u32(target, 0xbf000000 + reg, value);
+    if (err != ERROR_OK) {
+        LOG_ERROR("target_read_u32 failed");
+    }
+}
+#endif
+
+static int ath79_spi_bitbang_bytes(struct target *target, uint32_t io_base,
+                   int pre_deselect, int post_deselect,
+                   uint8_t *data, int len) {
+    LOG_DEBUG("ath79_spi_bitbang_bytes(%p, %08x, %d, %d, %p, %d)",
+        target, io_base, pre_deselect, post_deselect, data, len);
+    struct mips32_common *mips32 = target_to_mips32(target);
+    struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+
+    uint32_t pracc_out = 0;
+
+    const int pracc_pre_post = 26;
+    const int pracc_loop_byte = 8 * 2 + 2;
+
+    struct pracc_queue_info ctx = {.max_code = pracc_pre_post + len * pracc_loop_byte};
+    uint32_t *out = malloc(len + 3);
+    memset(out, 0xa5, len + 3);
+
+    pracc_queue_init(&ctx);
+    if (ctx.retval != ERROR_OK)
+        goto exit;
+
+    /* Calculate largest len given the available instruction budget. */
+    const int max_len = (PRACC_OUT_OFFSET / 4 - pracc_pre_post) / pracc_loop_byte;
+    if (len > max_len) {
+        LOG_INFO("len too big: %d > %d", len, max_len);
+        ctx.retval = ERROR_BUF_TOO_SMALL;
+        goto exit;
+    } else {
+        LOG_DEBUG("max len %d. len %d => max code %d", max_len, len, ctx.max_code);
+    }
+
+    pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR));  /* $15 = MIPS32_PRACC_BASE_ADDR */
+    pracc_add(&ctx, 0, MIPS32_LUI(1, UPPER16(io_base)));   /* $1 = io_base */
+    if (pre_deselect) {
+        /* [$1 + FS] = 1  (enable flash io register access) */
+        pracc_add(&ctx, 0, MIPS32_LUI(2, UPPER16(1)));
+        pracc_add(&ctx, 0, MIPS32_ORI(2, 2, LOWER16(1)));
+        pracc_add(&ctx, 0, MIPS32_SW(2, ATH79_REG_FS, 1));
+        /* deselect flash just in case */
+        pracc_add(&ctx, 0, MIPS32_LUI(2, UPPER16(AR7240_SPI_CS_DIS))); /* $2 = SPI_CS_DIS */
+        pracc_add(&ctx, 0, MIPS32_ORI(2, 2, LOWER16(AR7240_SPI_CS_DIS))); /* $2 = SPI_CS_DIS */
+        pracc_add(&ctx, 0, MIPS32_SW(2, ATH79_REG_WRITE, 1));  /* [$1 + WRITE] = $2 */
+    }
+    /* t0 = CLOCK_LOW + 0-bit */
+    pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16((AR7240_SPI_CE_LOW + 0))));
+    pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16((AR7240_SPI_CE_LOW + 0))));
+    /* t1 = CLOCK_LOW + 1-bit */
+    pracc_add(&ctx, 0, MIPS32_LUI(9, UPPER16((AR7240_SPI_CE_LOW + 1))));
+    pracc_add(&ctx, 0, MIPS32_ORI(9, 9, LOWER16((AR7240_SPI_CE_LOW + 1))));
+    /* t2 = CLOCK_HIGH + 0-bit */
+    pracc_add(&ctx, 0, MIPS32_LUI(10, UPPER16((AR7240_SPI_CE_HIGH + 0))));
+    pracc_add(&ctx, 0, MIPS32_ORI(10, 10, LOWER16((AR7240_SPI_CE_HIGH + 0))));
+    /* t2 = CLOCK_HIGH + 1-bit */
+    pracc_add(&ctx, 0, MIPS32_LUI(11, UPPER16((AR7240_SPI_CE_HIGH + 1))));
+    pracc_add(&ctx, 0, MIPS32_ORI(11, 11, LOWER16((AR7240_SPI_CE_HIGH + 1))));
+
+    for (int i = 0; i < len; i++) {
+        uint8_t x = data[i];
+        LOG_DEBUG("%d: generating code for %02x", i, x);
+        for (int j=0; j<8; j++) {
+            int bit = ((x << j) & 0x80) == 0x80;
+
+            LOG_DEBUG("  %d: generating code for bit %d", j, bit);
+            if (bit) {
+                /* [$1 + WRITE] = t1 */
+                pracc_add(&ctx, 0, MIPS32_SW(9, ATH79_REG_WRITE, 1));
+                /* [$1 + WRITE] = t3 */
+                pracc_add(&ctx, 0, MIPS32_SW(11, ATH79_REG_WRITE, 1));
+            } else {
+                /* [$1 + WRITE] = t0 */
+                pracc_add(&ctx, 0, MIPS32_SW(8, ATH79_REG_WRITE, 1));
+                /* [$1 + WRITE] = t2 */
+                pracc_add(&ctx, 0, MIPS32_SW(10, ATH79_REG_WRITE, 1));
+            }
+        }
+        if (i % 4 == 3) {
+            /* $3 = [$1 + DATA] */
+            pracc_add(&ctx, 0, MIPS32_LW(3, ATH79_REG_DATA, 1)); /* $3 = [$1 + DATA] */
+            /* [OUTi] = $3 */
+            pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + pracc_out,
+                    MIPS32_SW(3, PRACC_OUT_OFFSET + pracc_out, 15));
+            pracc_out += 4;
+        }
+    }
+    if (len & 3) { /* not a multiple of 4 bytes */
+        /* $3 = [$1 + DATA] */
+        pracc_add(&ctx, 0, MIPS32_LW(3, ATH79_REG_DATA, 1)); /* $3 = [$1 + DATA] */
+        /* [OUTi] = $3 */
+        pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + pracc_out,
+                MIPS32_SW(3, PRACC_OUT_OFFSET + pracc_out, 15));
+        pracc_out += 4;
+    }
+
+    if (post_deselect) {
+        pracc_add(&ctx, 0, MIPS32_LUI(2, UPPER16(AR7240_SPI_CS_DIS))); /* $2 = SPI_CS_DIS */
+        pracc_add(&ctx, 0, MIPS32_ORI(2, 2, LOWER16(AR7240_SPI_CS_DIS))); /* $2 = SPI_CS_DIS */
+        pracc_add(&ctx, 0, MIPS32_SW(2, ATH79_REG_WRITE, 1));  /* [$1 + WRITE] = $2 */
+
+        /* [$1 + FS] = 0  (disable flash io register access) */
+        pracc_add(&ctx, 0, MIPS32_XORI(2, 2, 0));
+        pracc_add(&ctx, 0, MIPS32_SW(2, ATH79_REG_FS, 1));
+    }
+
+    /* common pracc epilogue */
+    pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1)));            /* jump to start */
+    pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0));                    /* restore $15 from DeSave */
+
+    LOG_DEBUG("Assembled %d instructions, %d stores:", ctx.code_count, ctx.store_count);
+    for (int i = 0; i < ctx.code_count; i++) {
+        LOG_DEBUG("%08x", ctx.pracc_list[i]);
+    }
+
+    ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, out);
+    if (ctx.retval != ERROR_OK)
+        goto exit;
+
+    int pracc_words = pracc_out / 4;
+    if (len & 3) { /* not a multiple of 4 bytes */
+        /* Need to realign last word. */
+        out[pracc_words - 1] <<= 8 * (4 - len);
+    }
+    if (1234 != ntohl(1234)) {
+        /* byteswap buffer */
+        for (int i = 0; i < pracc_words; i++) {
+            out[i] = ntohl(out[i]);
+        }
+    }
+    for (int i = 0; i < len; i++) {
+        LOG_DEBUG("bitbang %02x => %02x",
+            data[i], ((uint8_t*)out)[i]);
+    }
+    memcpy(data, out, len);
+
+exit:
+    if (ctx.retval != ERROR_OK) {
+        memset(data, 0x5a, len);
+    }
+    if (out != NULL)
+        free(out);
+    pracc_queue_free(&ctx);
+    return ctx.retval;
+}
+
+#define SMI_POLL_TFF(timeout)
+#define SMI_SET_SW_MODE()
+#define SMI_SET_HWWB_MODE()
+#define SMI_SET_HW_MODE()
+#define SMI_CLEAR_TFF()
+
+#define SMI_BANK_SIZE      (0x01000000)
+
+#define SMI_CR1 (0x00) /* Control register 1 */
+#define SMI_CR2 (0x04) /* Control register 2 */
+#define SMI_SR  (0x08) /* Status register */
+#define SMI_TR  (0x0c) /* TX */
+#define SMI_RR  (0x10) /* RX */
+
+/* fields in SMI_CR1 */
+#define SMI_SW_MODE       0x10000000 /* set to enable SW Mode */
+#define SMI_WB_MODE       0x20000000 /* Write Burst Mode */
+
+/* fields in SMI_CR2 */
+#define SMI_TX_LEN_1      0x00000001 /* data length = 1 byte */
+#define SMI_TX_LEN_4      0x00000004 /* data length = 4 byte */
+#define SMI_RX_LEN_3      0x00000030 /* data length = 3 byte */
+#define SMI_SEND          0x00000080 /* Send data */
+#define SMI_RSR           0x00000400 /* reads status reg */
+#define SMI_WE            0x00000800 /* Write Enable */
+#define SMI_SEL_BANK0     0x00000000 /* Select Bank0 */
+#define SMI_SEL_BANK1     0x00001000 /* Select Bank1 */
+#define SMI_SEL_BANK2     0x00002000 /* Select Bank2 */
+#define SMI_SEL_BANK3     0x00003000 /* Select Bank3 */
+
+/* fields in SMI_SR */
+#define SMI_TFF           0x00000100 /* Transfer Finished Flag */
+
+/* Commands */
+#define SMI_READ_ID       0x0000009F /* Read Flash Identification */
+
+/* Timeout in ms */
+#define SMI_CMD_TIMEOUT   (100)
+#define SMI_PROBE_TIMEOUT (100)
+#define SMI_MAX_TIMEOUT  (3000)
+
+struct ath79_flash_bank {
+    int probed;
+    uint32_t io_base;
+    uint32_t bank_num;
+    const struct flash_device *dev;
+};
+
+struct ath79_target {
+    char *name;
+    uint32_t tap_idcode;
+    uint32_t smi_base;
+    uint32_t io_base;
+};
+
+static const struct ath79_target target_devices[] = {
+    /* name,          tap_idcode, smi_base,   io_base */
+    { "ATH79",        0x00000001, 0xbf000000, 0xbf000000 },
+    { NULL,           0,          0,          0 }
+};
+
+FLASH_BANK_COMMAND_HANDLER(ath79_flash_bank_command)
+{
+    struct ath79_flash_bank *ath79_info;
+
+    LOG_DEBUG("%s", __func__);
+
+    if (CMD_ARGC < 6)
+        return ERROR_COMMAND_SYNTAX_ERROR;
+
+    ath79_info = malloc(sizeof(struct ath79_flash_bank));
+    if (ath79_info == NULL) {
+        LOG_ERROR("not enough memory");
+        return ERROR_FAIL;
+    }
+
+    bank->driver_priv = ath79_info;
+    ath79_info->probed = 0;
+
+    return ERROR_OK;
+}
+
+/* Read the status register of the external SPI flash chip.
+ * The operation is triggered by setting SMI_RSR bit.
+ * SMI sends the proper SPI command (0x05) and returns value in SMI_SR */
+static int read_status_reg(struct flash_bank *bank, uint32_t *status)
+{
+    struct target *target = bank->target;
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    uint32_t io_base = ath79_info->io_base;
+
+    uint8_t spi_bytes[] = {SPIFLASH_READ_STATUS, 0};
+
+    /* Send SPI command "read STATUS" */
+    int retval = ath79_spi_bitbang_bytes(
+        target, io_base, 1, 1, spi_bytes, sizeof(spi_bytes));
+
+    *status = spi_bytes[1];
+
+    return retval;
+}
+
+/* check for WIP (write in progress) bit in status register */
+/* timeout in ms */
+static int wait_till_ready(struct flash_bank *bank, int timeout)
+{
+    uint32_t status;
+    int retval;
+    long long endtime;
+
+    endtime = timeval_ms() + timeout;
+    do {
+        /* read flash status register */
+        retval = read_status_reg(bank, &status);
+        if (retval != ERROR_OK)
+            return retval;
+
+        if ((status & SPIFLASH_BSY_BIT) == 0)
+            return ERROR_OK;
+        alive_sleep(1);
+    } while (timeval_ms() < endtime);
+
+    LOG_ERROR("timeout");
+    return ERROR_FAIL;
+}
+
+/* Send "write enable" command to SPI flash chip.
+ * The operation is triggered by setting SMI_WE bit, and SMI sends
+ * the proper SPI command (0x06) */
+static int smi_write_enable(struct flash_bank *bank)
+{
+    struct target *target = bank->target;
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    uint32_t io_base = ath79_info->io_base;
+    uint32_t status;
+    int retval;
+
+    uint8_t spi_bytes[] = {SPIFLASH_WRITE_ENABLE};
+
+    /* Send SPI command "write enable" */
+    retval = ath79_spi_bitbang_bytes(
+        target, io_base, 1, 1, spi_bytes, sizeof(spi_bytes));
+    if (retval != ERROR_OK)
+        return retval;
+
+    /* read flash status register */
+    retval = read_status_reg(bank, &status);
+    if (retval != ERROR_OK)
+        return retval;
+
+    /* Check write enabled */
+    if ((status & SPIFLASH_WE_BIT) == 0) {
+        LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status);
+        return ERROR_FAIL;
+    }
+
+    return ERROR_OK;
+}
+
+static int erase_command(struct flash_bank *bank, int sector)
+{
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    struct target *target = bank->target;
+    uint32_t io_base = ath79_info->io_base;
+    uint32_t offset = bank->sectors[sector].offset;
+
+    uint8_t spi_bytes[] = {
+        ath79_info->dev->erase_cmd,
+        offset >> 16,
+        offset >> 8,
+        offset
+    };
+
+    /* bitbang command */
+    return ath79_spi_bitbang_bytes(
+        target, io_base, 1, 1, spi_bytes, sizeof(spi_bytes));
+}
+
+static int smi_erase_sector(struct flash_bank *bank, int sector)
+{
+    int retval;
+
+    retval = smi_write_enable(bank);
+    if (retval != ERROR_OK)
+        return retval;
+
+    /* send SPI command "block erase" */
+    retval = erase_command(bank, sector);
+    if (retval != ERROR_OK)
+        return retval;
+
+    /* poll WIP for end of self timed Sector Erase cycle */
+    retval = wait_till_ready(bank, SMI_MAX_TIMEOUT);
+    if (retval != ERROR_OK)
+        return retval;
+
+    return ERROR_OK;
+}
+
+static int ath79_erase(struct flash_bank *bank, int first, int last)
+{
+    struct target *target = bank->target;
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    int retval = ERROR_OK;
+    int sector;
+
+    LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last);
+
+    if (target->state != TARGET_HALTED) {
+        LOG_ERROR("Target not halted");
+        return ERROR_TARGET_NOT_HALTED;
+    }
+
+    if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
+        LOG_ERROR("Flash sector invalid");
+        return ERROR_FLASH_SECTOR_INVALID;
+    }
+
+    if (!(ath79_info->probed)) {
+        LOG_ERROR("Flash bank not probed");
+        return ERROR_FLASH_BANK_NOT_PROBED;
+    }
+
+    for (sector = first; sector <= last; sector++) {
+        if (bank->sectors[sector].is_protected) {
+            LOG_ERROR("Flash sector %d protected", sector);
+            return ERROR_FAIL;
+        }
+    }
+
+    for (sector = first; sector <= last; sector++) {
+        retval = smi_erase_sector(bank, sector);
+        if (retval != ERROR_OK)
+            break;
+        keep_alive();
+    }
+
+    /* Switch to HW mode before return to prompt */
+    SMI_SET_HW_MODE();
+    return retval;
+}
+
+static int ath79_protect(struct flash_bank *bank, int set,
+    int first, int last)
+{
+    int sector;
+
+    for (sector = first; sector <= last; sector++)
+        bank->sectors[sector].is_protected = set;
+    return ERROR_OK;
+}
+
+static int ath79_write_page(struct flash_bank *bank, const uint8_t *buffer,
+    uint32_t address, uint32_t len)
+{
+    uint8_t spi_page_buf[0x100];
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    struct target *target = bank->target;
+    uint32_t io_base = ath79_info->io_base;
+    uint32_t written = 0;
+    uint8_t spi_cmd[] = {
+        SPIFLASH_PAGE_PROGRAM,
+        address >> 16,
+        address >> 8,
+        address,
+    };
+    int retval;
+
+    if (address & 0xff) {
+        LOG_ERROR("ath79_write_page: unaligned write address: %08x\n", address);
+        return ERROR_FAIL;
+    }
+
+    if (len > sizeof(spi_page_buf)) {
+        LOG_ERROR("ath79_write_page: length bigger than page size %ld: %d\n",
+            sizeof(spi_page_buf), len);
+        return ERROR_FAIL;
+    }
+
+    uint32_t i;
+    for (i = 0; i < len; i++) {
+        if (buffer[i] != 0xff)
+            break;
+    }
+    if (i == len)  /* all 0xff, no need to program. */
+        return ERROR_OK;
+
+    address -= ath79_info->io_base;
+
+    LOG_INFO("writing %d bytes to flash page @0x%08x", len, address);
+
+    memcpy(spi_page_buf, buffer, len);
+
+    /* unlock writes */
+    retval = smi_write_enable(bank);
+    if (retval != ERROR_OK)
+        return retval;
+
+    /* bitbang command */
+    retval = ath79_spi_bitbang_bytes(
+        target, io_base, 1, 0, spi_cmd, sizeof(spi_cmd));
+    if (retval != ERROR_OK)
+        return retval;
+
+    /* Length limit derived from pracc code size limit */
+    const uint32_t spi_max_len = 112;
+
+    while (len > spi_max_len) {
+        /* write blocks with len limited by pracc code size */
+        retval = ath79_spi_bitbang_bytes(
+            target, io_base, 0, 0, &spi_page_buf[written], spi_max_len);
+        if (retval != ERROR_OK)
+            return retval;
+
+        written += spi_max_len;
+        len -= spi_max_len;
+    }
+
+    /* write final block of data */
+    return ath79_spi_bitbang_bytes(
+        target, io_base, 0, 1, &spi_page_buf[written], len);
+}
+
+static int smi_write_buffer(struct flash_bank *bank, const uint8_t *buffer,
+    uint32_t address, uint32_t len)
+{
+    int retval;
+
+    LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32,
+            __func__, address, len);
+
+    while (len > 0) {
+        const uint32_t page_size = 0x100;
+
+        /* Page size is 256 bytes */
+        int page_len = len > 0x100 ? 0x100 : len;
+        retval = ath79_write_page(
+            bank, buffer, address, page_len);
+        if (retval != ERROR_OK)
+            return retval;
+
+        buffer += page_size;
+        address += page_size;
+        len -= page_len;
+    }
+
+    return ERROR_OK;
+}
+
+static int ath79_write(struct flash_bank *bank, const uint8_t *buffer,
+    uint32_t offset, uint32_t count)
+{
+    struct target *target = bank->target;
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    int sector;
+
+    LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+        __func__, offset, count);
+
+    if (target->state != TARGET_HALTED) {
+        LOG_ERROR("Target not halted");
+        return ERROR_TARGET_NOT_HALTED;
+    }
+
+    if (offset + count > ath79_info->dev->size_in_bytes) {
+        LOG_WARNING("Write pasts end of flash. Extra data discarded.");
+        count = ath79_info->dev->size_in_bytes - offset;
+    }
+
+    /* Check sector protection */
+    for (sector = 0; sector < bank->num_sectors; sector++) {
+        /* Start offset in or before this sector? */
+        /* End offset in or behind this sector? */
+        if ((offset <
+                (bank->sectors[sector].offset + bank->sectors[sector].size))
+            && ((offset + count - 1) >= bank->sectors[sector].offset)
+            && bank->sectors[sector].is_protected) {
+            LOG_ERROR("Flash sector %d protected", sector);
+            return ERROR_FAIL;
+        }
+    }
+
+    return smi_write_buffer(bank, buffer, bank->base + offset, count);
+}
+
+/* Return ID of flash device */
+/* On exit, SW mode is kept */
+static int read_flash_id(struct flash_bank *bank, uint32_t *id)
+{
+    struct target *target = bank->target;
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    uint32_t io_base = ath79_info->io_base;
+    int retval;
+    uint8_t spi_bytes[] = {SPIFLASH_READ_ID, 0, 0, 0, 0, 0, 0, 0};
+    /* Read 8 bytes @0xbf060000 */
+    uint8_t spi_test[] = {3, 6, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0};
+    uint8_t spi_buf[12];
+
+    if (target->state != TARGET_HALTED) {
+        LOG_ERROR("Target not halted");
+        return ERROR_TARGET_NOT_HALTED;
+    }
+    memcpy(spi_buf, spi_test, sizeof(spi_test));
+    ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+            spi_buf, 5);
+
+    memcpy(spi_buf, spi_test, sizeof(spi_test));
+    ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+            spi_buf, 6);
+
+    memcpy(spi_buf, spi_test, sizeof(spi_test));
+    ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+            spi_buf, 7);
+
+    memcpy(spi_buf, spi_test, sizeof(spi_test));
+    ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+            spi_buf, 8);
+
+    memcpy(spi_buf, spi_test, sizeof(spi_test));
+    ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+            spi_buf, 9);
+
+    memcpy(spi_buf, spi_test, sizeof(spi_test));
+    ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+            spi_buf, 10);
+
+    memcpy(spi_buf, spi_test, sizeof(spi_test));
+    ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+            spi_buf, 11);
+
+    memcpy(spi_buf, spi_test, sizeof(spi_test));
+    ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+            spi_buf, 12);
+
+    /* Send SPI command "read ID" */
+    retval = ath79_spi_bitbang_bytes(target, io_base, 1, 1,
+                spi_bytes, sizeof(spi_bytes));
+    if (retval != ERROR_OK)
+        return retval;
+
+    *id = (spi_bytes[1] << 0)
+        | (spi_bytes[2] << 8)
+        | (spi_bytes[3] << 16);
+    LOG_ERROR("read_flash_id: %06x", *id);
+
+    return ERROR_OK;
+}
+
+static int ath79_probe(struct flash_bank *bank)
+{
+    struct target *target = bank->target;
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    uint32_t io_base;
+    struct flash_sector *sectors;
+    uint32_t id = 0; /* silence uninitialized warning */
+    const struct ath79_target *target_device;
+    int retval;
+
+    if (ath79_info->probed)
+        free(bank->sectors);
+    ath79_info->probed = 0;
+
+    for (target_device = target_devices ; target_device->name ; ++target_device)
+        if (target_device->tap_idcode == target->tap->idcode)
+            break;
+    if (!target_device->name) {
+        LOG_ERROR("Device ID 0x%" PRIx32 " is not known as SMI capable",
+                target->tap->idcode);
+        return ERROR_FAIL;
+    }
+
+    io_base = target_device->io_base;
+    ath79_info->io_base = io_base;
+
+    LOG_DEBUG("Valid SMI on device %s at address 0x%" PRIx32,
+        target_device->name, bank->base);
+
+    /* read and decode flash ID; returns in SW mode */
+    retval = read_flash_id(bank, &id);
+    SMI_SET_HW_MODE();
+    if (retval != ERROR_OK)
+        return retval;
+
+    ath79_info->dev = NULL;
+    for (const struct flash_device *p = flash_devices; p->name ; p++)
+        if (p->device_id == id) {
+            ath79_info->dev = p;
+            break;
+        }
+
+    if (!ath79_info->dev) {
+        LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
+        return ERROR_FAIL;
+    }
+
+    LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
+        ath79_info->dev->name, ath79_info->dev->device_id);
+
+    /* Set correct size value */
+    bank->size = ath79_info->dev->size_in_bytes;
+
+    /* create and fill sectors array */
+    bank->num_sectors =
+        ath79_info->dev->size_in_bytes / ath79_info->dev->sectorsize;
+    sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+    if (sectors == NULL) {
+        LOG_ERROR("not enough memory");
+        return ERROR_FAIL;
+    }
+
+    for (int sector = 0; sector < bank->num_sectors; sector++) {
+        sectors[sector].offset = sector * ath79_info->dev->sectorsize;
+        sectors[sector].size = ath79_info->dev->sectorsize;
+        sectors[sector].is_erased = -1;
+        sectors[sector].is_protected = 1;
+    }
+
+    bank->sectors = sectors;
+    ath79_info->probed = 1;
+    return ERROR_OK;
+}
+
+static int ath79_auto_probe(struct flash_bank *bank)
+{
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+    if (ath79_info->probed)
+        return ERROR_OK;
+    return ath79_probe(bank);
+}
+
+static int ath79_protect_check(struct flash_bank *bank)
+{
+    /* Nothing to do. Protection is only handled in SW. */
+    return ERROR_OK;
+}
+
+static int get_ath79_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+    struct ath79_flash_bank *ath79_info = bank->driver_priv;
+
+    if (!(ath79_info->probed)) {
+        snprintf(buf, buf_size,
+            "\nSMI flash bank not probed yet\n");
+        return ERROR_OK;
+    }
+
+    snprintf(buf, buf_size, "\nSMI flash information:\n"
+        "  Device \'%s\' (ID 0x%08" PRIx32 ")\n",
+        ath79_info->dev->name, ath79_info->dev->device_id);
+
+    return ERROR_OK;
+}
+
+struct flash_driver ath79_flash = {
+    .name = "ath79",
+    .flash_bank_command = ath79_flash_bank_command,
+    .erase = ath79_erase,
+    .protect = ath79_protect,
+    .write = ath79_write,
+    .read = default_flash_read,
+    .probe = ath79_probe,
+    .auto_probe = ath79_auto_probe,
+    .erase_check = default_flash_blank_check,
+    .protect_check = ath79_protect_check,
+    .info = get_ath79_info,
+};
diff -x minidriver_imp.h -x xscale_debug.inc -x startup_tcl.inc -x startup.tcl -x openocd -x Makefile.in -x Makefile -Nru openocd-0.9.0-vanilla/src/flash/nor/drivers.c openocd-0.9.0/src/flash/nor/drivers.c
--- openocd-0.9.0-vanilla/src/flash/nor/drivers.c    2015-04-24 17:09:54.000000000 +0200
+++ openocd-0.9.0/src/flash/nor/drivers.c    2015-10-23 09:15:35.390154487 +0200
@@ -22,6 +22,7 @@
 #endif
 #include "imp.h"
 
+extern struct flash_driver ath79_flash;
 extern struct flash_driver lpc2000_flash;
 extern struct flash_driver lpc288x_flash;
 extern struct flash_driver lpc2900_flash;
@@ -65,6 +66,7 @@
  * @todo Make this dynamically extendable with loadable modules.
  */
 static struct flash_driver *flash_drivers[] = {
+    &ath79_flash,
     &lpc2000_flash,
     &lpc288x_flash,
     &lpc2900_flash,
diff -x minidriver_imp.h -x xscale_debug.inc -x startup_tcl.inc -x startup.tcl -x openocd -x Makefile.in -x Makefile -Nru openocd-0.9.0-vanilla/src/flash/nor/Makefile.am openocd-0.9.0/src/flash/nor/Makefile.am
--- openocd-0.9.0-vanilla/src/flash/nor/Makefile.am    2015-04-24 17:09:54.000000000 +0200
+++ openocd-0.9.0/src/flash/nor/Makefile.am    2015-10-23 09:14:52.291677642 +0200
@@ -29,6 +29,7 @@
     pic32mx.c \
     spi.c \
     stmsmi.c \
+    ath79.c \
     stellaris.c \
     stm32f1x.c \
     stm32f2x.c \
diff -x minidriver_imp.h -x xscale_debug.inc -x startup_tcl.inc -x startup.tcl -x openocd -x Makefile.in -x Makefile -Nru openocd-0.9.0-vanilla/src/flash/nor/spi.c openocd-0.9.0/src/flash/nor/spi.c
--- openocd-0.9.0-vanilla/src/flash/nor/spi.c    2015-04-24 17:09:54.000000000 +0200
+++ openocd-0.9.0/src/flash/nor/spi.c    2015-10-23 10:03:08.459651011 +0200
@@ -74,6 +74,7 @@
     FLASH_ID("win w25q32fv",   0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000),
     FLASH_ID("win w25q32dw",   0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000),
     FLASH_ID("win w25q64cv",   0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000),
+    FLASH_ID("win w25q128",    0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000),
     FLASH_ID("gd gd25q20",     0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000),
     FLASH_ID(NULL,             0,    0,       0,          0,     0,       0)
 };

Re: Debrick Routers with AR724x processors Using JTAG

When make me have error:

...
libtool: compile:  gcc -std=gnu99 -DHAVE_CONFIG_H -I. -I../../.. -I../../../src -I../../../src -I../../../src/helper -DPKGDATADIR=\"/usr/local/share/openocd\" -DBINDIR=\"/usr/local/bin\" -I../../../jimtcl -I../../../jimtcl -g -O2 -Wall -Wstrict-prototypes -Wformat-security -Wshadow -Wextra -Wno-unused-parameter -Wbad-function-cast -Wcast-align -Wredundant-decls -Werror -MT ath79.lo -MD -MP -MF .deps/ath79.Tpo -c ath79.c -o ath79.o
ath79.c: In function 'ath79_write_page':
ath79.c:516:9: error: format '%ld' expects argument of type 'long int', but argument 6 has type 'unsigned int' [-Werror=format=]
         LOG_ERROR("ath79_write_page: length bigger than page size %ld: %d\n",
         ^
cc1: all warnings being treated as errors
make[5]: *** [ath79.lo] Error 1
make[5]: Leaving directory `/home/xubuntu/openocd/src/flash/nor'
make[4]: *** [all-recursive] Error 1
make[4]: Leaving directory `/home/xubuntu/openocd/src/flash'
make[3]: *** [all-recursive] Error 1
make[3]: Leaving directory `/home/xubuntu/openocd/src'
make[2]: *** [all] Error 2
make[2]: Leaving directory `/home/xubuntu/openocd/src'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/xubuntu/openocd'
make: *** [all] Error 2

xubuntu@xubuntu:~/openocd$

Re: Debrick Routers with AR724x processors Using JTAG

https://wiki.openwrt.org/doc/recipes/de … using.jtag
Instruction, thx moroboshi

18 (edited by freezer2k 2016-04-18 16:47:52)

Re: Debrick Routers with AR724x processors Using JTAG

Hi,

Awesome work.

Successfully unbricked my TL-WDR3600, vastly based on your code/instructions, moroboshi! Thanks for sharing.

Wrote down my adventure here:
https://forum.openwrt.org/viewtopic.php … 40#p320240

Please note my remarks about the write_image 'erase' option! Not sure if this is required, but seems like a good idea?

Otherwise, after fiddling with the (E)JTAG connection for quite a while, the target config and ath79.patch worked unmodified for this router, guessing this will be the case for a lot of Routers built upon these SoCs! smile


PS: Started out using the Rpi1 for the JTAG interface, very very slow read/write operations.
The Rpi3 was still very slow,  but about 4times faster (even though its single-threaded). Flashing uboot via the Pi1 will probably take about an hour. I want some fast Odroid for this stuff.

Re: Debrick Routers with AR724x processors Using JTAG

freezer2k wrote:

Hi,
PS: Started out using the Rpi1 for the JTAG interface, very very slow read/write operations.
The Rpi3 was still very slow,  but about 4times faster (even though its single-threaded). Flashing uboot via the Pi1 will probably take about an hour. I want some fast Odroid for this stuff.

I was using a USB FT2232 to JTAG adapter.
Rpi1 should be plenty fast as well, I'd suspect the JTAG interface driver to be not very optimized?
I didn't try compiling on 32bit, so that explains the printf format issue.