2012年10月29日 星期一

AM335X RTC-Only mode suspend ...... part #1

經過漫長的半個月的移植 , 終於可以動作了 , 並且可以正常的 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

2012年10月11日 星期四

再度開啟AM335x 專案......

經過幾個月的等待  ,  TI 是出了 RTC-only mode 的 code , 不過....
我感覺是派幾個工程師 為我們需求寫的 , 並且確定在 下一版 official release 中不會有 rtc-mode 的 code.

所以表示 , 我們又是白老鼠 ?? 幫 TI 驗證這段 rtc-mode 的 code @@

真是有點無力.......

rtc-mode 主要在RTC block 內有 三個 register (RTC_SCRATCH0 ~ 3 )  是給使用者存東西的 , 在這 3 個 register 中放入 resume function address & 一些判別的資料 .

修改 u-boot , 在 reset 時候這些暫存器內容如果正確 , 直接回  DDR resume address function. 就可以叫醒 CPU 了 .

當然 suspend 的時候直接控制 PMIC , 將 CPU 電源都切除 (RTC block 除外) , 這樣就會省許多電力.

當 user 要 resume 的時候 , 就將 CPU 所有電源打開,  並且發 reset  給 CPU  , CPU 由 ROM Code 開始跑.....

u-boot 檢查到CPU RTC 內的那三個 register 正確 , 就直接回 DDR resume function, 整個 system 就可以 resume 了.


說的簡單 , 實際上 困難重重 ,首先 要對一些暫存器 , 設定 PMIC 的 sleep mode .
光儲存必要暫存器的值 .... 就翻天了.....
那麼多暫存器....那都能了解 , 並且  clock domain , power domain 還有 M3 這樣多的東西, 等我弄懂....往生了..... @@

TI 給的 code 又超亂 (臨時 加上去  , 並且感覺手動測試一下就丟出來了 , 反正不是 official release ) ,  我要 patch 半天.... 才搞懂改了那些 .

不過 , 看 patch file , 修改我的 code , 難免有錯誤.....
debug 才是大問題 , 一切靠自己了 @@