經過漫長的半個月的移植 , 終於可以動作了 , 並且可以正常的 sleep & resume .
過程很多細節的問題 , 都克服了 , 這篇文章紀錄一些目前我覺得重點和詭異的地方.
A. 首先 , 我將 TI 給我的 kernel source code , 移植到我們的 source code 中 !!
雖然這個版本並非 official release , 有點不穩定 , 不過總比沒有東西好 , 其中的
bug , 只好自己解決 , 或是 call FAE 一起解決了 .
移植過程中 , 我為了舊有的 deep sleep mode 還存在 , 所以我自己增加一個
echo "rtconly" > /sys/power/state 來區分 之前的 "mem" (Deep sleep mode ).
移植完畢後 , 卻沒有辦法 sleep , 下 command 給PMIC , 要 PMIC 進入sleep mode ,
卻失敗 , 經過一段時間 delay 後就回 kernel 了. (參考下列的 code , 不過是 組合語言 )
原來 , PMIC 要進入 sleep mode , 須要有幾個condiction , 除了 DEV_SLP 外 ,
還需要 SLEEP Pin 的配合 , 修改 H/W , 讓 Sleep 空接 , PMIC Power on default
SLEEP pin 會 pull_low.
進入 sleep mode 後發現 mDDR Power 被關閉 , 試著修改一些 KEEP_ON 暫存器 還是
沒有用 , 經過 Study , 有可能 PMIC 直接 進入 off state , 並非 sleep state !!
果然 , PWRHOLD Pin 需要輸入 high , 讓 PMIC 不要回到 off state !!
搞定上面的問題後終於可以 sleep 了 , 並且 mDDR power 也持續供應 .
問題來了 , wake up 卻........死當 !!
在 u-boot , kernel 中 將 kernel resume 中的 physical add 中的 前 4 byte printf 出來
看看 , 是否 mDDR 有正確 keep data !!
內容值都一樣 , 表示 mDDR 有 keep data , 那.....哪邊死當呢 ????
(下篇說明 , 這個詭異的問題 )
//--------------------------------
/* Put the PLLs in bypass mode */
//--------------------------------
put_pll_bypass:
pll_bypass core, virt_core_clk_mode, virt_core_idlest, core_val
pll_bypass ddr, virt_ddr_clk_mode, virt_ddr_idlest, ddr_val
pll_bypass disp, virt_disp_clk_mode, virt_disp_idlest, disp_val
pll_bypass per, virt_per_clk_mode, virt_per_idlest, per_val
pll_bypass mpu, virt_mpu_clk_mode, virt_mpu_idlest, mpu_val
//---- check sleep mode .
//---- PM_SUSPEND_MEM = 3 , deep sleep mode .
//---- PM_SUSPEND_RTCONLY = 4 , rtc only mode.
ldr r0, sleep_mode
cmp r0, #3
beq deepsleep
//--------------------------------
/* RTC Only mode sleep. */
ldr r0, i2c0_clk_addr_virt
mov r1, #2
str r1, [r0]
/* set clock registers */
ldr r0, i2c0_addr_virt
mov r1, #3
strh r1, [r0, #I2C_PSC]
mov r1, #54
strh r1, [r0, #I2C_SCLL]
mov r1, #54
strh r1, [r0, #I2C_SCLH]
/* set own address */
mov r1, #1
strh r1, [r0, #I2C_OA]
/* take out of reset */
mov r1, #0x8000
strh r1, [r0, #I2C_CON]
/* only enable xrdy interrupt */
ldrh r1, [r0, #I2C_IRQENABLE_SET]
strh r1, [r0, #I2C_IRQENABLE_CLR]
mov r1, #0x1F
strh r1, [r0, #I2C_IRQENABLE_SET]
/* disable auto idle. starterware does this */
ldrh r1, [r0, #I2C_SYSC]
bic r1, r1, #1
strh r1, [r0, #I2C_SYSC]
/* write the sleep sequence */
mov r1, #0x2D
mov r2, #0x50 @ TPS65910_INT_STS
mov r3, #0xFF @ clear all irq event .
bl am33xx_i2c0_write
mov r1, #0x2D
mov r2, #0x52 @ TPS65910_INT_STS2
mov r3, #0xFF @ clear all irq event.
bl am33xx_i2c0_write
mov r1, #0x2D
mov r2, #0x43 @ TPS65910_SLEEP_SET_LDO_OFF
// mov r3, #0xFF @ turn off LDO in sleep mode.
mov r3, #0xDF @ turn off LDO in sleep mode.
bl am33xx_i2c0_write
mov r1, #0x2D
mov r2, #0x42 @ TPS65910_SLEEP_KEEP_RES_ON
mov r3, #0x00 @
bl am33xx_i2c0_write
mov r1, #0x2D
mov r2, #0x44 @ TPS65910_SLEEP_SET_RES_OFF
mov r3, #0x0E
bl am33xx_i2c0_write
mov r1, #0x2D
mov r2, #0x3F @ TPS65910_DEVCTRL
// mov r3, #0x62
mov r3, #0x32
bl am33xx_i2c0_write
/* Wait a bit, then abort */
mov r0, #0x100000
wait_i2c0:
subs r0, r0, #1
bne wait_i2c0
b abort
沒有留言:
張貼留言