]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00221161 [MX6SL]- Add audio bus freq mode support.
authorRanjani Vaidyanathan <ra5478@freescale.com>
Wed, 22 Aug 2012 18:26:11 +0000 (13:26 -0500)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:19 +0000 (08:35 +0200)
Set DDR to 50MHz in low power audio playback.
AHB/AXI are at 24MHz.
Also fix correct usecount for PLL1 main clock. If not
it causes issues when pll1_sw_clk's parent is changed.

Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
arch/arm/mach-mx6/bus_freq.c
arch/arm/mach-mx6/clock_mx6sl.c
arch/arm/mach-mx6/mx6sl_ddr.S
arch/arm/mach-mx6/mx6sl_wfi.S
arch/arm/mach-mx6/system.c

index 53a65fb893f6fdd7204f4cb7d157d0e6e73f51f2..8c04e51d8827c7f6e8f201e94e9212e3988b3d03 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/suspend.h>
 
 #define LPAPM_CLK              24000000
+#define DDR_AUDIO_CLK  50000000
 #define DDR_MED_CLK            400000000
 #define DDR3_NORMAL_CLK                528000000
 #define GPC_PGC_GPU_PGCR_OFFSET        0x260
@@ -81,7 +82,7 @@ void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr) = NULL;
 extern void mx6sl_wait (int arm_podf, unsigned long wfi_iram_addr);
 
 void *mx6sl_ddr_freq_base;
-void (*mx6sl_ddr_freq_change_iram)(int ddr_freq) = NULL;
+void (*mx6sl_ddr_freq_change_iram)(int ddr_freq, int low_bus_freq_mode) = NULL;
 extern void mx6sl_ddr_iram(int ddr_freq);
 
 extern int init_mmdc_settings(void);
@@ -140,13 +141,13 @@ static void reduce_bus_freq_handler(struct work_struct *work)
                if (lp_audio_freq) {
                        /* Need to ensure that PLL2_PFD_400M is kept ON. */
                        clk_enable(pll2_400);
-                       update_ddr_freq(50000000);
+                       update_ddr_freq(DDR_AUDIO_CLK);
                        /* Make sure periph clk's parent also got updated */
                        clk_set_parent(periph_clk, pll2_200);
                        audio_bus_freq_mode = 1;
                        low_bus_freq_mode = 0;
                } else {
-                       update_ddr_freq(24000000);
+                       update_ddr_freq(LPAPM_CLK);
                        /* Make sure periph clk's parent also got updated */
                        clk_set_parent(periph_clk, osc_clk);
                        if (audio_bus_freq_mode)
@@ -167,32 +168,61 @@ static void reduce_bus_freq_handler(struct work_struct *work)
 
                spin_lock_irqsave(&freq_lock, flags);
 
-               /* Set periph_clk to be sourced from OSC_CLK */
-               /* Set AXI to 24MHz. */
-               clk_set_parent(periph_clk, osc_clk);
-               clk_set_rate(axi_clk, clk_round_rate(axi_clk, LPAPM_CLK));
-               /* Set AHB to 24MHz. */
-               clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, LPAPM_CLK));
-
-               /* Set MMDC clk to 24MHz. */
-               /* Since we are going to set PLL2 in bypass mode,
-                 * move the CPU clock off PLL2.
-                 */
-               /* Ensure that the clock will be at lowest possible freq. */
-               org_arm_podf = __raw_readl(MXC_CCM_CACRR);
-               div = clk_get_rate(pll1) / cpu_op_tbl[cpu_op_nr - 1].cpu_rate;
-
-               reg = __raw_writel(div - 1, MXC_CCM_CACRR);
-               while (__raw_readl(MXC_CCM_CDHIPR))
-                       ;
-               clk_set_parent(pll1_sw_clk, pll1);
+               if (high_bus_freq_mode) {
+                       /* Set periph_clk to be sourced from OSC_CLK */
+                       /* Set AXI to 24MHz. */
+                       clk_set_parent(periph_clk, osc_clk);
+                       clk_set_rate(axi_clk,
+                               clk_round_rate(axi_clk, LPAPM_CLK));
+                       /* Set AHB to 24MHz. */
+                       clk_set_rate(ahb_clk,
+                               clk_round_rate(ahb_clk, LPAPM_CLK));
+               }
+               if (lp_audio_freq) {
+                       /* PLL2 is on in this mode, as DDR is at 50MHz. */
+                       /* Now change DDR freq while running from IRAM. */
+                       mx6sl_ddr_freq_change_iram(DDR_AUDIO_CLK,
+                                                       low_bus_freq_mode);
+
+                       if (low_bus_freq_mode) {
+                               /* Swtich ARM to run off PLL2_PFD2_400MHz
+                                * since DDR is anway at 50MHz.
+                                */
+                               clk_set_parent(pll1_sw_clk, pll2_400);
+
+                               /* Ensure that the clock will be
+                                 * at original speed.
+                                 */
+                               reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR);
+                               while (__raw_readl(MXC_CCM_CDHIPR))
+                                       ;
+                       }
+                       low_bus_freq_mode = 0;
+                       audio_bus_freq_mode = 1;
+               } else {
+                       /* Set MMDC clk to 24MHz. */
+                       /* Since we are going to set PLL2 in bypass mode,
+                         * move the CPU clock off PLL2.
+                         */
+                       /* Ensure that the clock will be at
+                         * lowest possible freq.
+                         */
+                       org_arm_podf = __raw_readl(MXC_CCM_CACRR);
+                       div = clk_get_rate(pll1) /
+                                       cpu_op_tbl[cpu_op_nr - 1].cpu_rate;
 
-               /* Now change DDR freq while running from IRAM. */
-               mx6sl_ddr_freq_change_iram(LPAPM_CLK);
+                       reg = __raw_writel(div - 1, MXC_CCM_CACRR);
+                       while (__raw_readl(MXC_CCM_CDHIPR))
+                               ;
+                       clk_set_parent(pll1_sw_clk, pll1);
 
-               low_bus_freq_mode = 1;
-               audio_bus_freq_mode = 0;
+                       /* Now change DDR freq while running from IRAM. */
+                       mx6sl_ddr_freq_change_iram(LPAPM_CLK,
+                                       low_bus_freq_mode);
 
+                       low_bus_freq_mode = 1;
+                       audio_bus_freq_mode = 0;
+               }
                spin_unlock_irqrestore(&freq_lock, flags);
        }
        high_bus_freq_mode = 0;
@@ -258,9 +288,8 @@ int set_high_bus_freq(int high_bus_freq)
                unsigned long flags;
 
                spin_lock_irqsave(&freq_lock, flags);
-
                /* Change DDR freq in IRAM. */
-               mx6sl_ddr_freq_change_iram(ddr_normal_rate);
+               mx6sl_ddr_freq_change_iram(ddr_normal_rate, low_bus_freq_mode);
 
                /* Set periph_clk to be sourced from pll2_pfd2_400M */
                /* First need to set the divider before changing the */
@@ -271,18 +300,18 @@ int set_high_bus_freq(int high_bus_freq)
                             clk_round_rate(axi_clk, LPAPM_CLK / 2));
                clk_set_parent(periph_clk, pll2_400);
 
-               /* Now move ARM to be sourced from PLL2_400 too. */
-               clk_set_parent(pll1_sw_clk, pll2_400);
-
-               /* Ensure that the clock will be at original speed. */
-               reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR);
-               while (__raw_readl(MXC_CCM_CDHIPR))
-                       ;
+               if (low_bus_freq_mode) {
+                       /* Now move ARM to be sourced from PLL2_400 too. */
+                       clk_set_parent(pll1_sw_clk, pll2_400);
 
+                       /* Ensure that the clock will be at original speed. */
+                       reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR);
+                       while (__raw_readl(MXC_CCM_CDHIPR))
+                               ;
+               }
                high_bus_freq_mode = 1;
                low_bus_freq_mode = 0;
                audio_bus_freq_mode = 0;
-
                spin_unlock_irqrestore(&freq_lock, flags);
        } else {
                clk_enable(pll3);
index d93320d59dd809171d9fa92be254385944deffa0..4839f1542b3a7d6f167a6bbdc64e4b18936016cf 100755 (executable)
@@ -1236,6 +1236,7 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
                pll1_sys_main_clk.disable(&pll1_sys_main_clk);
                pll1_sys_main_clk.usecount = 0;
        }
+
        spin_unlock_irqrestore(&mx6sl_clk_lock, flags);
 
        return 0;
@@ -2451,7 +2452,7 @@ static struct clk ssi1_clk = {
 #else
         .secondary = &mmdc_ch1_axi_clk[0],
 #endif
-       .flags  = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+       .flags  = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
 };
 
 static unsigned long _clk_ssi2_get_rate(struct clk *clk)
@@ -2525,7 +2526,7 @@ static struct clk ssi2_clk = {
 #else
         .secondary = &mmdc_ch1_axi_clk[0],
 #endif
-       .flags  = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+       .flags  = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
 };
 
 static unsigned long _clk_ssi3_get_rate(struct clk *clk)
@@ -2598,7 +2599,7 @@ static struct clk ssi3_clk = {
 #else
         .secondary = &mmdc_ch1_axi_clk[0],
 #endif
-       .flags  = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+       .flags  = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE,
 };
 
 static unsigned long _clk_epdc_lcdif_pix_round_rate(struct clk *clk,
index 78208c192b39fc3ef3bd34c2f0ba39e7ce1e8794..3059f3aa3c8cde68e8f31cf3ae62482d467a79af 100644 (file)
@@ -102,10 +102,27 @@ periph2_clk_switch3:
      cmp     r6, #0
      bne     periph2_clk_switch3
 
+     /* Now set the MMDC PODF back to 1.*/
+      ldr    r6, [r2, #0x14]
+      bic    r6, r6, #0x38
+      str    r6, [r2, #0x14]
+
+mmdc_podf0:
+     ldr     r6, [r2, #0x48]
+     cmp     r6, #0
+     bne     mmdc_podf0
+
        .endm
 
          .macro        ddr_switch_400MHz
 
+     /* Check if we are switching between
+       * 400Mhz <-> 50MHz. If so, we only need to
+       * update MMDC divider.
+       */
+      cmp    r1, #0
+      beq     change_divider_only
+
     /* Set MMDC divider first, in case PLL3 is at 480MHz. */
       ldr     r6, [r3, #0x10]
       and    r6, r6, #0x10000
@@ -191,10 +208,26 @@ periph2_clk_switch6:
      cmp     r6, #0
      bne     periph2_clk_switch6
 
-     /* Now set the MMDC PODF back to 1.*/
-
+change_divider_only:
+    /* Calculate the MMDC divider
+     * based on the requested freq.
+     */
+    ldr    r6, =400000000
+    ldr    r4, =0
+Loop2:
+    sub    r6, r6, r0
+    cmp   r6, r0
+    blt     Div_Found
+    add    r4, r4, #1
+    bgt     Loop2
+
+     /* Shift divider into correct offset. */
+     lsl    r4, r4, #3
+Div_Found:
+     /* Set the MMDC PODF. */
       ldr    r6, [r2, #0x14]
       bic    r6, r6, #0x38
+      orr    r6, r6, r4
       str    r6, [r2, #0x14]
 
 mmdc_podf1:
@@ -204,41 +237,63 @@ mmdc_podf1:
 
     .endm
 
-        .macro   mmdc_clk_lower_100MHz
-
-        /* Prior to reducing the DDR frequency (at 528/400 MHz),
-           read the Measure unit count bits (MU_UNIT_DEL_NUM) */
-        ldr     r5, =0x8B8
-        ldr   r6, [r8, r5]
-        /* Original MU unit count */
-        mov     r6, r6, LSR #16
-        ldr     r4, =0x3FF
-        and     r6, r6, r4
-        /* Original MU unit count * 2 */
-        mov     r1, r6, LSL #1
-        /* Bypass the automatic measure unit when below 100 MHz
-           by setting the Measure unit bypass enable bit (MU_BYP_EN) */
-        ldr     r6, [r8, r5]
-        orr     r6, r6, #0x400
-        str     r6, [r8, r5]
-     /* Double the measure count value read in step 1 and program it in the
-        measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit
-        Register for the reduced frequency operation below 100 MHz */
-        ldr     r6, [r8, r5]
-        ldr     r4, =0x3FF
-        bic     r6, r6, r4
-        orr     r6, r6, r1
-        str     r6, [r8, r5]
-        .endm
-
-        .macro   mmdc_clk_above_100MHz
-
-        /* Make sure that the PHY measurement unit is NOT in bypass mode */
-        ldr     r5, =0x8B8
-        ldr     r6, [r8, r5]
-        bic     r6, r6, #0x400
-        str     r6, [r8, r5]
-        .endm
+      .macro   mmdc_clk_lower_100MHz
+
+      /* Prior to reducing the DDR frequency (at 528/400 MHz),
+      read the Measure unit count bits (MU_UNIT_DEL_NUM) */
+      ldr     r5, =0x8B8
+      ldr     r6, [r8, r5]
+      /* Original MU unit count */
+      mov   r6, r6, LSR #16
+      ldr     r4, =0x3FF
+      and    r6, r6, r4
+      /* Original MU unit count * 2 */
+      mov    r7, r6, LSL #1
+      /* Bypass the automatic measure unit when below 100 MHz
+      by setting the Measure unit bypass enable bit (MU_BYP_EN) */
+      ldr     r6, [r8, r5]
+      orr     r6, r6, #0x400
+      str     r6, [r8, r5]
+      /* Double the measure count value read in step 1 and program it in the
+        * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit
+        * Register for the reduced frequency operation below 100 MHz
+        */
+       ldr    r6, [r8, r5]
+       ldr    r4, =0x3FF
+       bic    r6, r6, r4
+       orr    r6, r6, r7
+       str     r6, [r8, r5]
+      /* Now perform a Force Measurement. */
+      ldr     r6, [r8, r5]
+      orr    r6, r6, #0x800
+      str     r6, [r8, r5]
+      /* Wait for FRC_MSR to clear. */
+force_measure:
+      ldr     r6, [r8, r5]
+      and    r6, r6, #0x800
+      cmp   r6, #0x0
+      bne    force_measure
+
+       .endm
+
+      .macro   mmdc_clk_above_100MHz
+
+      /* Make sure that the PHY measurement unit is NOT in bypass mode */
+      ldr     r5, =0x8B8
+      ldr     r6, [r8, r5]
+      bic    r6, r6, #0x400
+      str     r6, [r8, r5]
+      /* Now perform a Force Measurement. */
+      ldr     r6, [r8, r5]
+      orr    r6, r6, #0x800
+      str     r6, [r8, r5]
+      /* Wait for FRC_MSR to clear. */
+force_measure1:
+      ldr     r6, [r8, r5]
+      and    r6, r6, #0x800
+      cmp   r6, #0x0
+      bne    force_measure1
+      .endm
 
 /*
  *  mx6sl_ddr_iram
@@ -247,6 +302,7 @@ mmdc_podf1:
  *  Make sure DDR is in self-refresh.
  *  IRQs are already disabled.
  * r0 : DDR freq.
+ * r1: low_bus_freq_mode flag
  */
 ENTRY(mx6sl_ddr_iram)
 
@@ -285,7 +341,7 @@ mx6sl_ddr_freq_change:
      str    r6, [r8, #0x4]
 
      /* Delay for a while */
-     ldr      r1, =10
+     ldr      r10, =10
 delay1:
      ldr      r7, =0
 cont1:
@@ -293,8 +349,8 @@ cont1:
      add     r7, r7, #4
      cmp    r7, #16
      bne     cont1
-     sub     r1, r1, #1
-     cmp    r1, #0
+     sub     r10, r10, #1
+     cmp    r10, #0
      bgt     delay1
 
      /* Make the DDR explicitly enter self-refresh. */
@@ -313,16 +369,24 @@ poll_dvfs_set_1:
      orr     r6, r6, #0x100
      str     r6, [r8, #0x410]
 
-     ldr     r1, =24000000
-     cmp    r0, r1
+     ldr     r10, =100000000
+     cmp   r0, r10
+     bgt    set_ddr_mu_above_100
+     mmdc_clk_lower_100MHz
+
+set_ddr_mu_above_100:
+     ldr     r10, =24000000
+     cmp    r0, r10
      beq     set_to_24MHz
 
-     mmdc_clk_above_100MHz
      ddr_switch_400MHz
+     ldr     r10,  =100000000
+     cmp  r0, r10
+     blt     done
+     mmdc_clk_above_100MHz
      b    done
 
 set_to_24MHz:
-     mmdc_clk_lower_100MHz
      mx6sl_switch_to_24MHz
 
 done:
@@ -342,8 +406,8 @@ poll_dvfs_clear_1:
      bic    r6, r6, #0x01
      str    r6, [r8, #0x404]
 
-     ldr     r1, =24000000
-     cmp    r0, r1
+     ldr     r10, =24000000
+     cmp    r0, r10
      beq     skip_power_down
 
      /* Enable MMDC power down timer. */
index 610a57f1373000dc1cca09ac7ade2826f910a080..d2d910383cb7b627eb8a681abb38e62908304150 100644 (file)
@@ -201,6 +201,11 @@ poll_dvfs_set_1:
      cmp    r6, #0x2000000
      bne     poll_dvfs_set_1
 
+     /* set SBS step-by-step mode */
+     ldr     r6, [r8, #0x410]
+     orr     r6, r6, #0x100
+     str     r6, [r8, #0x410]
+
      /* Now set DDR rate to 1MHz. */
      /* DDR is from bypassed PLL2 on periph2_clk2 path.
        * Set the periph2_clk2_podf to divide by 8.
@@ -215,6 +220,12 @@ poll_dvfs_set_1:
      orr    r6, r6, #0x10
      str     r6, [r2, #0x14]
 
+    /* Loop till podf is accepted. */
+mmdc_podf:
+     ldr     r6, [r2, #0x48]
+     cmp   r6, #0x0
+     bne   mmdc_podf
+
       /* Set the DDR IO in LPM state. */
      sl_ddr_io_set_lpm
 
@@ -321,6 +332,11 @@ ahb_podf1:
      bic   r6, r6, #0x3f
      str    r6, [r2, #0x14]
 
+mmdc_podf1:
+     ldr     r6, [r2, #0x48]
+     cmp   r6, #0x0
+     bne   mmdc_podf1
+
      /* clear DVFS - exit from self refresh mode */
      ldr     r6, [r8, #0x404]
      bic     r6, r6, #0x200000
@@ -337,6 +353,12 @@ poll_dvfs_clear_1:
      bic    r6, r6, #0x01
      str    r6, [r8, #0x404]
 
+     /* clear SBS - unblock DDR accesses */
+     ldr     r6, [r8, #0x410]
+     bic     r6, r6, #0x100
+     str     r6, [r8, #0x410]
+
+
     pop {r4,r5, r6, r7, r8, r9, r10}
 
     /* Restore registers */
index 75701dc6485a3fb2bd8b11e126bd3c36a5971158..686c58c1e0e5d9275b4457a4aef6060f3d2138a6 100644 (file)
@@ -252,18 +252,38 @@ void arch_idle_single_core(void)
 
                ca9_do_idle();
        } else {
-               if (low_bus_freq_mode && cpu_is_mx6sl()) {
-                       u32 org_arm_podf = __raw_readl(MXC_CCM_CACRR);
+               if (low_bus_freq_mode || audio_bus_freq_mode) {
+                       if (cpu_is_mx6sl() && low_bus_freq_mode) {
+                               /* In this mode PLL2 i already in bypass,
+                                 * ARM is sourced from PLL1. The code in IRAM
+                                 * will set ARM to be sourced from STEP_CLK
+                                 * at 24MHz. It will also set DDR to 1MHz to
+                                 * reduce power.
+                                 */
+                               u32 org_arm_podf = __raw_readl(MXC_CCM_CACRR);
 
-                       /* Need to run WFI code from IRAM so that
-                         * we can lower DDR freq.
-                         */
-                       mx6sl_wfi_iram(org_arm_podf,
-                               (unsigned long)mx6sl_wfi_iram_base);
+                               /* Need to run WFI code from IRAM so that
+                                 * we can lower DDR freq.
+                                 */
+                               mx6sl_wfi_iram(org_arm_podf,
+                                       (unsigned long)mx6sl_wfi_iram_base);
+                       } else {
+                               /* Need to set ARM to run at 24MHz since IPG
+                                 * is at 12MHz. This is valid for audio mode on
+                                 * MX6SL, and all low power modes on MX6DLS.
+                                 */
+                               /* PLL1_SW_CLK is sourced from PLL2_PFD2400MHz
+                                 * at this point. Move it to bypassed PLL1.
+                                 */
+                               reg = __raw_readl(MXC_CCM_CCSR);
+                               reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
+                               __raw_writel(reg, MXC_CCM_CCSR);
 
-                       /* Clear the chicken bit to allow memories
-                         * to be powered down
-                         */
+                               ca9_do_idle();
+
+                               reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
+                               __raw_writel(reg, MXC_CCM_CCSR);
+                       }
                } else {
                        /*
                          * Implement the 12:5 ARM:IPG_CLK ratio