arm: tegra: Set Core to 0.95V in LP1
[linux-3.10.git] / arch / arm / mach-tegra / sleep-t30.S
index 817b85b..8071112 100644 (file)
 #define PMC_PLLM_WB0_OVERRIDE          0x1dc
 
 #define CLK_RESET_CLK_SOURCE_MSELECT   0x3b4
+#define CLK_RESET_CLK_ENB_H_SET                0x328
+#define CLK_RESET_CLK_ENB_H_CLR                0x32c
+#define CLK_RESET_CLK_RST_DEV_H_SET            0x308
+#define CLK_RESET_CLK_RST_DEV_H_CLR            0x30c
+
+#define I2C_CNFG       0x0
+#define I2C_ADDR0      0x4
+#define I2C_DATA1      0xc
+#define I2C_DATA2      0x10
+#define I2C_STATUS     0x1c
 
 #define MSELECT_CLKM                   (0x3 << 30)
 
@@ -395,6 +405,66 @@ ENTRY(tegra3_lp1_reset)
        mov32   r4, ((1<<28) | (8))     @ burst policy is PLLX
        str     r4, [r0, #CLK_RESET_CCLK_BURST]
 
+#ifdef CONFIG_TEGRA_LP1_950
+lp1_voltset:
+       /* Restore the Core voltage to high on LP1 resume */
+       /* Reset(Enable/Disable) the DVC-I2C Controller*/
+       mov r1, #(1 << 15)
+       str r1, [r0, #CLK_RESET_CLK_RST_DEV_H_SET]
+
+       /* Wait for 2us */
+       mov32   r7, TEGRA_TMRUS_BASE
+       wait_for_us r1, r7, r9
+       add r1, r1, #2
+       wait_until r1, r7, r9
+
+       mov r1, #(1 << 15)
+       str r1, [r0, #CLK_RESET_CLK_RST_DEV_H_CLR]
+
+       /* Enable the DVC-I2C Controller */
+       mov r1, #(1 << 15)
+       str r1, [r0, #CLK_RESET_CLK_ENB_H_SET]
+
+
+       /* Same I2C transaction protocol as suspend */
+       ldr r1, lp1_register_pmuslave_addr
+       cmp r1, #0
+       beq lp1_voltskip_resume
+
+       ldr r4, lp1_register_i2c_base_addr
+       str r1, [r4, #I2C_ADDR0]
+
+       mov32 r1, 0x2
+       str r1, [r4, #I2C_CNFG]
+
+       ldr r1, lp1_register_core_highvolt
+       str r1, [r4, #I2C_DATA1]
+
+       mov32 r1, 0
+       str r1, [r4, #I2C_DATA2]
+
+       mov32 r1, 0xA02
+       str r1, [r4, #I2C_CNFG]
+
+       wait_for_us r1, r7, r9
+       mov32 r3, 0x7D0   /* Wait for 2ms and try transaction again */
+       add r0, r1, r3
+loop_i2c_status_resume:
+       add r1, r1, #0xFA /* Check status every 250us */
+       wait_until r1, r7, r9
+       cmp r0, r1
+       beq lp1_voltset
+
+       ldr r3, [r4, #I2C_STATUS]
+       cmp r3, #0
+       bne loop_i2c_status_resume
+
+lp1_voltskip_resume:
+       /* Disable the DVC-I2C Controller */
+       mov r0, #(1 << 15)
+       str r0, [r5, #CLK_RESET_CLK_ENB_H_CLR]
+#endif
+
 #if defined (CONFIG_CACHE_L2X0)
        /* power up L2 */
        ldr     r0, [r2, #PMC_PWRGATE_STATUS]
@@ -539,6 +609,21 @@ tegra3_sdram_pad_address:
 tegra3_sdram_pad_size:
        .word   tegra3_sdram_pad_address - tegra3_sdram_pad_save
 
+#ifdef CONFIG_TEGRA_LP1_950
+       .globl lp1_register_pmuslave_addr
+       .globl lp1_register_i2c_base_addr
+       .globl lp1_register_core_lowvolt
+       .globl lp1_register_core_highvolt
+lp1_register_pmuslave_addr:
+       .word   0
+lp1_register_i2c_base_addr:
+       .word   0
+lp1_register_core_lowvolt:
+       .word   0
+lp1_register_core_highvolt:
+       .word   0
+#endif
+
 /*
  * tegra3_tear_down_core
  *
@@ -573,9 +658,72 @@ tegra3_cpu_clk32k:
        str     r0, [r4, #PMC_PLLM_WB0_OVERRIDE]
        mov     pc, lr
 
+lp1_clocks_prepare:
+       /* Prepare to set the Core to the lowest voltage if supported.
+        * Start by setting the I2C clocks to make the I2C transfer */
+#ifdef CONFIG_TEGRA_LP1_950
+       /* Set up the PWR I2C GPIOs with the right masks*/
+
+       /* Reset(Set/Clr) the DVC-I2C Controller*/
+       mov r0, #(1 << 15)
+       str r0, [r5, #CLK_RESET_CLK_RST_DEV_H_SET]
+
+       /* Wait for 2us */
+       wait_for_us r1, r7, r9
+       mov32 r0, 0x7D0
+       add r1, r1, r0
+       wait_until r1, r7, r9
+
+       mov r0, #(1 << 15)
+       str r0, [r5, #CLK_RESET_CLK_RST_DEV_H_CLR]
+
+       /* Enable the DVC-I2C Controller */
+       mov r0, #(1 << 15)
+       str r0, [r5, #CLK_RESET_CLK_ENB_H_SET]
+
+       /* I2C transfer protocol:
+        * 4 packets: Slaveaddr + WriteConfigure + Data1 + Data2 */
+       ldr r0, lp1_register_pmuslave_addr
+       cmp r0, #0
+       beq lp1_volt_skip
+       ldr r1, lp1_register_i2c_base_addr
+       str r0, [r1, #I2C_ADDR0]
+
+       mov32 r0, 0x2
+       str r0, [r1, #I2C_CNFG]
+
+       ldr r0, lp1_register_core_lowvolt
+       str r0, [r1, #I2C_DATA1]
+
+       mov32 r0, 0
+       str r0, [r1, #I2C_DATA2]
+
+       /* Send I2C transaction */
+       mov32 r0, 0xA02
+       str r0, [r1, #I2C_CNFG]
+
+       /* Check the transaction status before proceeding */
+       wait_for_us r2, r7, r9
+       mov32 r3, 0x7D0 /* Wait for 2ms for I2C transaction */
+       add r3, r2, r3
+loop_i2c_status_suspend:
+       add r2, r2, #0xFA /* Check status every 250us */
+       cmp r3, r2
+       beq lp1_volt_skip  /* Waited for 2ms, I2C transaction didn't take place */
+       wait_until r2, r7, r9
+
+       ldr r0, [r1, #I2C_STATUS]
+       cmp r0, #0
+       bne loop_i2c_status_suspend
+lp1_volt_skip:
+
+       /* Disable the DVC-I2C Controller */
+       mov r0, #(1 << 15)
+       str r0, [r5, #CLK_RESET_CLK_ENB_H_CLR]
+
+#endif
        /* start by jumping to clkm to safely disable PLLs, then jump
         * to clks */
-lp1_clocks_prepare:
        mov     r0, #(1 << 28)
        str     r0, [r5, #CLK_RESET_SCLK_BURST]
        str     r0, [r5, #CLK_RESET_CCLK_BURST]