I’ve been trying to get the OMAP-L138 to do a software reset for some time now in our Linux environment. Some quick background: The design uses the ROM bootloaders to first initate the system, then the OMAP-L138 UBL bootloader loads UBOOT, which UBOOT then loads Linux. This is the path I'd like to mimic for my software reset by jumping to the ARM ROM bootloader.
However, due to hardware restrictions in our design (where I can't use the watchdog or PLL registers to kick off the reset) the only remaining option that is available to use is the cpu_arm926_reset macro in our linux distribution.
Sometimes the reset works, but the majority of the time, it hangs. Here’s a forum post very similar to my situation.
http://lists.infradead.org/pipermail/linux-arm-kernel/2009-November/003952.html
I’ve used CCSv5 to verify that the jump is being made to the ARM ROM bootloader address where it starts executing. However, the system gets stuck in a loop at address 0xFFFD3978.
Here’s the disassembly from CCSv5:
0xfffd3978: E1A00000 MOV R0, R0
EAFFFFFD B 0xfffd3978
1.) What is this is or where it’s stuck and why it would get here?
2.) Is jumping to the ARM ROM bootloader the best way to do the software reset considering my limitations? Is it possible to jump to the DSP one which I believe then jumps to the ARM bootloader? Maybe there’s a setup issue that the DSP does during a cold boot to the ARM?
3.) If I can’t use the DSP ROM bootloader, could another issue be the state of external RAM, internal RAM (e.g. junk data?) Would internal/external RAM need to be cleared out prior to jumping to the ROM bootloaders?
4.) Is there an easy way set all the registers to defaults so the OMAP behaves like it's coming out of a cold reset?
------------------
Below is the code I'm using to do the resets now (which is currently inconsistent).
-------------------
// disable interrupts
__asm__ __volatile__(
"mrs r0, cpsr\n\t"
"orr r0, r0, #0xc0\n\t"
"msr cpsr_c, r0"
);
// flush all cache then jump to the ROM bootloader
cpu_arm926_proc_fin();
cpu_arm926_reset(0xFFFD0000);
-------------------
These are the macro definitions in my Linux distrbution.
*/
/* cpu_arm926_proc_fin()
*/
ENTRY(cpu_arm926_proc_fin)
mrc p15, 0, r0, c1, c0, 0 @ ctrl register
bic r0, r0, #0x1000 @ ...i............
bic r0, r0, #0x000e @ ............wca.
mcr p15, 0, r0, c1, c0, 0 @ disable caches
mov pc, lr
-------------------
/*
* cpu_arm926_reset(loc)
*
* Perform a soft reset of the system. Put the CPU into the
* same state as it would be if it had been reset, and branch
* to what would be the reset vector.
*
* loc: location to jump to for soft reset
*/
.align 5
.pushsection .idmap.text, "ax"
ENTRY(cpu_arm926_reset)
mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches
mcr p15, 0, ip, c7, c10, 4 @ drain WB
#ifdef CONFIG_MMU
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
#endif
mrc p15, 0, ip, c1, c0, 0 @ ctrl register
bic ip, ip, #0x000f @ ............wcam
bic ip, ip, #0x1100 @ ...i...s........
mcr p15, 0, ip, c1, c0, 0 @ ctrl register
mov pc, r0
ENDPROC(cpu_arm926_reset)
.popsection