Hi James,
You will notice in one of the posts before this, where Soren mentioned:
"I managed to get it working: The issue in my case was, that the CPU pll was PLL2, and when this was bypassed the ARM clock was lower than PLL1SYSCLK4. The result of this was, that any reading or writing to a peripheral clocked from PLL1SYSCLK4 (see figure 5 in SPRUFG5A) would become unreliable. Especially note that the DDR2 EMIF is clocked by PLL1SYSCLK4. My solution was to switch the CPU to PLL1 also, such that when bypassed the CPU is still clocked sufficiently higher than PLL1SYSCLK4."
So before you bypass the CPU PLL, let the CPU and DDR run from the same PLL, by clearing the ARMCLKS bit in the PERI_CLKCTL register of the system control module.
- Switch the CPU PLL to bypass - writes 0s to PLLCTL_PLLENSRC and PLLCTL_PLLEN (PLL2)
- Wait 4 cycles for Bypass
- Power down the CPU PLL - writes 1 to PLLCTL_PLLPWRDN
- Configure sleep count in the deep sleep register - writes 128 into the deepsleep register
I used a sleepcount of 4096, to ensure that the osillator is stable before enabling clocks.
- call sleep.S file - goes into SRAM
- store all registers
- call arm926_flush_kern_cache_all
You make no mention of branching to ip (blx ip) between the following steps. I noticed that if that line (blx ip) is included, the processor hangs, so I commented it out.
- load r0 - r4 with the information passed in from pdata
- Put DDR into self-refresh - write 0 to SRPD and 1 to LPMODEN in SDRCR
- Stop MCLK - write 1 to MCLKSTOPEN in SDRCR
- wait 4096 cycles
I actually wait 1000 cycles. I don't see any harm in waiting longer, but I do know that if you want to load a value greater than 1000 to ip, you cannot use the mv command.
- Disable DDR2 LPSC
I noticed that you disable the clock to DDR PHY (PLLDIV7) after putting the DDR into bypass mode. I'm not sure if that is an issue, but I do it before.
- Put DDR into bypass mode - write 0 pllctl_pllensrc and pllctl_pllen (PLL1)
- wait 4 cycles for bypass
- Put PLL into reset - write 1 to PLLCTL_PLLRST (PLL1)
Also, I don't see the need to put the PLL into reset.
- Disable clock to DDR PHY - write 0 to PLLDIV_EN
- Power down DDR PLL - write 1 to PLLCTL_PLLPWRDN (PLL1)
- Go to deep sleep - write 1 to DEEPSLEEP_SPEELENABLE_BIT
- Stay in loop polling DEEPSLEEP_SLEEPCOMPLETE_BIT
- Transition GIO0 from high to low, wait more than 500ns, then low to high
- Clear sleep enable - write 0 to DEEPSLEEP_SLEEPENABLE_BIT
- Clear PLL power down - write 0 to PLLCTL_PLLPWRDN
After waking up and clearing PLL power down, I wait 4 clock cycles.
- Put PLL into bypass mode - write 0 to PLLCTL_PLLENSRC and PLLCTL_PLLEN (PLL1)
There is no need to put the PLL back into bypass mode.
- Put PLL into reset - write 1 to PLLCTL_PLLRST (PLL1)
- wait 125 cycles for reset to take place
- Take PLL out of reset - write 0 to PLLCTL_PLLRST (PLL1)
/* Program "sequence" to allow PLL to lock at desired frequency */
mov ip, #0x00470000 /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 1 */
str ip, [r3, #PLLSECCTL]
mov ip, #0x00460000 /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 0 */
str ip, [r3, #PLLSECCTL]
mov ip, #0x00400000 /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 0 */
str ip, [r3, #PLLSECCTL]
mov ip, #0x00410000 /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 1 */
str ip, [r3, #PLLSECCTL]
/* Set the GOSET bit */
mov ip, #1
str ip, [r3, #PLLCMD]
Wait for PLL lock
Remove PLL from bypass
- Start DDR PHY - write 1 to PLLDIV_EN
- Wait 600 cycles for PLL to lock
- Remove PLL from bypass - write 0 to PLLCTL_PLLENSRC and 1 to PLLCTL_PLLEN (PLL1)
- Enable DDR2 LPSC
- Enable MCLK - write 0 to MCLKSTOPEN
Poll SDRSTAT to check that MCLK is started
- Bring DDR2 out of self-refresh - write 0 to LPMODEEN and 1 to SRPD
At this point I actually wait 2000 cycles.
- Restore registers and return
I also wait here for 100 microseconds.
- Remove CPU PLL from power down - write 0 to PLLCTL_PLLPWRDN (PLL2)
- Put CPU PLL into bypass - write 0 to PLLCTL_PLLENSRC (PLL2)
No need to put PLL into bypass
- wait 4 clock cycles
- Put CPU PLL in reset - write 1 to PLLCTL_PLLRST (PLL2)
- wait 25 clock cycles
- Bring CPU PLL out of reset - write 0 to PLLCTL_PLLRST (PLL2)
- PLLSECCTL pattern (TENABLE, TENABLEDIV, TINITZ): (1,1,1); (1,1,0); (0,0,0); (0,0,1)
Set the GOSET bit
- POLL LOCK1, LOCK2, LOCK3 of the system module PLLC2_CONFIG registers until all 1s
- Remove PLL from bypass - write 0 to PLLCTL_PLLENSRC and PLLCTL_PLLEN (PLL2)
- wait 4 clock cycles
Switch clock source of CPU back to PLL2
- Return to normal functionality
This seems to either hang up after trying to return to normal functionality or after I try to put the CPU PLL into bypass mode after powering the CPU PLL back up.
I suggest that you work from the outside in, to figure out where exactly your problem lies. So, as an initial test, comment out the code that puts the unit into SRAM (davinci_sram_suspend(pdata);) and check that you can successfully put the CPU PLL into bypass and successfully take it out of bypass.
Hope this helps
Regards
Arshad