]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00220696 [MX6SL]-Reduce IDLE mode power consumption.
authorRanjani Vaidyanathan <ra5478@freescale.com>
Wed, 8 Aug 2012 19:56:15 +0000 (14:56 -0500)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:17 +0000 (08:35 +0200)
When ARM enters WFI in low power IDLE state, float the DDR
IO pins to drop the power on the VDDHIGH rail.
Need to run WFI code from IRAM since DDR needs to be
put into self-refresh before changing the IO pins.
Drop AHB to 8MHz and DDR to 1MHz when ARM is in WFI when
in IDLE state.
Set IPG_PERCLK to run at 3MHz, since we want to maintain a
1:2.5 ratio between PERCLK to AHB_CLK.

Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
arch/arm/mach-mx6/Makefile
arch/arm/mach-mx6/bus_freq.c
arch/arm/mach-mx6/clock_mx6sl.c
arch/arm/mach-mx6/mx6sl_wfi.S [new file with mode: 0644]
arch/arm/mach-mx6/system.c

index 91fc841e952906e0fd42c4b2e078ca3d832fa522..49b5f86a6920c149ee816fbb5268de52a3c4d8b7 100644 (file)
@@ -5,7 +5,7 @@
 # Object file lists.
 obj-y   := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o usb_dr.o usb_h2.o usb_h3.o\
 pm.o cpu_op-mx6.o mx6_wfi.o mx6_fec.o mx6_anatop_regulator.o cpu_regulator-mx6.o \
-mx6_mmdc.o mx6_ddr_freq.o mx6sl_ddr.o
+mx6_mmdc.o mx6_ddr_freq.o mx6sl_ddr.o mx6sl_wfi.o
 
 obj-$(CONFIG_ARCH_MX6) += clock.o mx6_suspend.o clock_mx6sl.o
 obj-$(CONFIG_MACH_MX6Q_ARM2) += board-mx6q_arm2.o
index b85c8ec8fd7c8ac6cfd666b38d494f16126c7b07..fa11d89e119102ac2b86ea98590b2cefa16d1ee8 100644 (file)
@@ -75,6 +75,9 @@ unsigned int ddr_normal_rate;
 
 int low_freq_bus_used(void);
 void set_ddr_freq(int ddr_freq);
+void *mx6sl_wfi_iram_base;
+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;
@@ -84,7 +87,6 @@ extern int init_mmdc_settings(void);
 extern struct cpu_op *(*get_cpu_op)(int *op);
 extern int update_ddr_freq(int ddr_rate);
 extern int chip_rev;
-extern bool arm_mem_clked_in_wait;
 
 DEFINE_MUTEX(bus_freq_mutex);
 
@@ -153,8 +155,6 @@ static void reduce_bus_freq_handler(struct work_struct *work)
                u32  div;
                unsigned long flags;
 
-               arm_mem_clked_in_wait = true;
-
                spin_lock_irqsave(&freq_lock, flags);
 
                /* Set periph_clk to be sourced from OSC_CLK */
@@ -177,7 +177,7 @@ static void reduce_bus_freq_handler(struct work_struct *work)
                        ;
                clk_set_parent(pll1_sw_clk, pll1);
 
-               /* Now change DDR freq in IRAM. */
+               /* Now change DDR freq while running from IRAM. */
                mx6sl_ddr_freq_change_iram(LPAPM_CLK);
 
                low_bus_freq_mode = 1;
@@ -308,9 +308,6 @@ int set_high_bus_freq(int high_bus_freq)
                clk_disable(pll3);
        }
 
-       if (cpu_is_mx6sl())
-               arm_mem_clked_in_wait = false;
-
        mutex_unlock(&bus_freq_mutex);
        return 0;
 }
@@ -618,7 +615,6 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
        if (!cpu_is_mx6sl())
                init_mmdc_settings();
        else {
-#if 1
                unsigned long iram_paddr;
 
                /* Allocate IRAM for WFI code when system is
@@ -628,12 +624,22 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
                /* Need to remap the area here since we want
                   * the memory region to be executable.
                   */
+               mx6sl_wfi_iram_base = __arm_ioremap(iram_paddr,
+                                               SZ_4K, MT_MEMORY_NONCACHED);
+               memcpy(mx6sl_wfi_iram_base, mx6sl_wait, SZ_4K);
+               mx6sl_wfi_iram = (void *)mx6sl_wfi_iram_base;
+
+               /* Allocate IRAM for WFI code when system is
+                 *in low freq mode.
+                 */
+               iram_alloc(SZ_4K, &iram_paddr);
+               /* Need to remap the area here since we want the memory region
+                        to be executable. */
                mx6sl_ddr_freq_base = __arm_ioremap(iram_paddr,
                                        SZ_4K, MT_MEMORY_NONCACHED);
                memcpy(mx6sl_ddr_freq_base, mx6sl_ddr_iram, SZ_4K);
                mx6sl_ddr_freq_change_iram = (void *)mx6sl_ddr_freq_base;
 
-#endif
        }
 
        return 0;
index 8fab0f287ecdddab499b5a1d61704b06edfe7bad..33721a4e212f6168640f52cd94afe9cbf3b09481 100755 (executable)
@@ -4000,6 +4000,12 @@ int __init mx6sl_clocks_init(unsigned long ckil, unsigned long osc,
         * should be from OSC24M */
        clk_set_parent(&ipg_perclk, &osc_clk);
 
+       /* Need to set IPG_PERCLK to 3MHz, so that we can
+         * satisfy the 2.5:1 AHB:IPG_PERCLK ratio. Since AHB
+         * can be dropped to as low as 8MHz in low power mode.
+         */
+       clk_set_rate(&ipg_perclk, 3000000);
+
        gpt_clk[0].parent = &ipg_perclk;
        gpt_clk[0].get_rate = NULL;
 
diff --git a/arch/arm/mach-mx6/mx6sl_wfi.S b/arch/arm/mach-mx6/mx6sl_wfi.S
new file mode 100644 (file)
index 0000000..610a57f
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/linkage.h>
+#include <mach/hardware.h>
+#define IRAM_WAIT_SIZE         (1 << 11)
+
+
+       .macro  sl_ddr_io_save
+
+       ldr     r4, [r1, #0x30c] /* DRAM_DQM0 */
+       ldr     r5, [r1, #0x310] /* DRAM_DQM1 */
+       ldr     r6, [r1, #0x314] /* DRAM_DQM2 */
+       ldr     r7, [r1, #0x318] /* DRAM_DQM3 */
+       stmfd   r9!, {r4-r7}
+
+       ldr     r4, [r1, #0x344] /* DRAM_SDQS0 */
+       ldr     r5, [r1, #0x348] /* DRAM_SDQS1 */
+       ldr     r6, [r1, #0x34c] /* DRAM_SDQS2 */
+       ldr     r7, [r1, #0x350] /* DRAM_SDQS3 */
+       stmfd   r9!, {r4-r7}
+
+       ldr     r4, [r1, #0x5c4] /* GPR_B0DS */
+       ldr     r5, [r1, #0x5cc] /* GPR_B1DS */
+       ldr     r6, [r1, #0x5d4] /* GPR_B2DS */
+       ldr     r7, [r1, #0x5d8] /* GPR_B3DS */
+       stmfd   r9!, {r4-r7}
+
+       ldr     r4, [r1, #0x300] /* DRAM_CAS */
+       ldr     r5, [r1, #0x31c] /* DRAM_RAS */
+       ldr     r6, [r1, #0x338] /* DRAM_SDCLK_0 */
+       ldr r7, [r1, #0x5ac] /* GPR_ADDS*/
+       stmfd   r9!, {r4-r7}
+
+       ldr     r4, [r1, #0x5b0] /* DDRMODE_CTL */
+       ldr     r5, [r1, #0x5c0] /* DDRMODE */
+       ldr     r6, [r1, #0x33c] /* DRAM_SODT0*/
+       ldr     r7, [r1, #0x340] /* DRAM_SODT1*/
+       stmfd   r9!, {r4-r7}
+
+       ldr     r4, [r1, #0x330] /* DRAM_SDCKE0 */
+       ldr     r5, [r1, #0x334] /* DRAM_SDCKE1 */
+       ldr     r6, [r1, #0x320] /* DRAM_RESET */
+       ldr     r7, [r1, #0x5c8] /* GPR_CTLDS */
+       stmfd   r9!, {r4-r7}
+
+       .endm
+
+       .macro  sl_ddr_io_restore
+
+       ldmea   r9!, {r4-r7}
+       str     r4, [r1, #0x30c] /* DRAM_DQM0 */
+       str     r5, [r1, #0x310] /* DRAM_DQM1 */
+       str     r6, [r1, #0x314] /* DRAM_DQM2 */
+       str     r7, [r1, #0x318] /* DRAM_DQM3 */
+
+       ldmea   r9!, {r4-r7}
+       str     r4, [r1, #0x344] /* DRAM_SDQS0 */
+       str     r5, [r1, #0x348] /* DRAM_SDQS1 */
+       str     r6, [r1, #0x34c] /* DRAM_SDQS2 */
+       str     r7, [r1, #0x350] /* DRAM_SDQS3 */
+
+       ldmea   r9!, {r4-r7}
+       str     r4, [r1, #0x5c4] /* GPR_B0DS */
+       str     r5, [r1, #0x5cc] /* GPR_B1DS */
+       str r6, [r1, #0x5d4] /* GPR_B2DS */
+       str r7, [r1, #0x5d8] /* GPR_B3DS */
+
+       ldmea   r9!, {r4-r7}
+       str     r4, [r1, #0x300] /* DRAM_CAS */
+       str     r5, [r1, #0x31c] /* DRAM_RAS */
+       str     r6, [r1, #0x338] /* DRAM_SDCLK_0 */
+       str r7, [r1, #0x5ac] /* GPR_ADDS*/
+
+       ldmea   r9!, {r4-r7}
+       str     r4, [r1, #0x5b0] /* DDRMODE_CTL */
+       str     r5, [r1, #0x5c0] /* DDRMODE */
+       str     r6, [r1, #0x33c] /* DRAM_SODT0*/
+       str     r7, [r1, #0x340] /* DRAM_SODT1*/
+
+       ldmea   r9!, {r4-r7}
+       str     r4, [r1, #0x330] /* DRAM_SDCKE0 */
+       str     r5, [r1, #0x334] /* DRAM_SDCKE1 */
+       str     r6, [r1, #0x320] /* DRAM_RESET */
+       str     r7, [r1, #0x5c8] /* GPR_CTLDS */
+
+       .endm
+
+       .macro  sl_ddr_io_set_lpm
+
+       mov     r4, #0
+       str     r4, [r1, #0x30c] /* DRAM_DQM0 */
+       str     r4, [r1, #0x310] /* DRAM_DQM1 */
+       str     r4, [r1, #0x314] /* DRAM_DQM2 */
+       str     r4, [r1, #0x318] /* DRAM_DQM3 */
+
+       str     r4, [r1, #0x344] /* DRAM_SDQS0 */
+       str     r4, [r1, #0x348] /* DRAM_SDQS1 */
+       str     r4, [r1, #0x34c] /* DRAM_SDQS2 */
+       str     r4, [r1, #0x350] /* DRAM_SDQS3 */
+
+       str     r4, [r1, #0x5c4] /* GPR_B0DS */
+       str     r4, [r1, #0x5cc] /* GPR_B1DS */
+       str r4, [r1, #0x5d4] /* GPR_B2DS */
+       str r4, [r1, #0x5d8] /* GPR_B3DS */
+
+       str     r4, [r1, #0x300] /* DRAM_CAS */
+       str     r4, [r1, #0x31c] /* DRAM_RAS */
+       str     r4, [r1, #0x338] /* DRAM_SDCLK_0 */
+       str r4, [r1, #0x5ac] /* GPR_ADDS*/
+
+       str     r4, [r1, #0x5b0] /* DDRMODE_CTL */
+       str     r4, [r1, #0x5c0] /* DDRMODE */
+       str     r4, [r1, #0x33c] /* DRAM_SODT0*/
+       str     r4, [r1, #0x340] /* DRAM_SODT1*/
+
+       str     r4, [r1, #0x5c8] /* GPR_CTLDS */
+       mov     r4, #0x80000
+       str     r4, [r1, #0x320] /* DRAM_RESET */
+       mov     r4, #0x1000
+       str     r4, [r1, #0x330] /* DRAM_SDCKE0 */
+       str     r4, [r1, #0x334] /* DRAM_SDCKE1 */
+
+       .endm
+
+/*
+ *  mx6sl_wait
+ *
+ *  Idle the processor (eg, wait for interrupt).
+ *  Make sure DDR is in self-refresh.
+ *  IRQs are already disabled.
+ * r0 : arm_podf before WFI is entered
+ * r1: WFI IRAMcode base address.
+ */
+ENTRY(mx6sl_wait)
+
+    push {r4, r5, r6, r7, r8, r9, r10}
+
+mx6sl_lpm_wfi:
+    /* Get the IRAM data storage address. */
+    mov    r10, r1
+    mov        r9, r1          /* get suspend_iram_base */
+     add       r9, r9, #IRAM_WAIT_SIZE /* 4K */
+
+    ldr     r1, =MX6Q_IOMUXC_BASE_ADDR
+    add   r1, r1, #PERIPBASE_VIRT
+
+      /* Save the DDR IO state. */
+     sl_ddr_io_save
+
+    ldr     r3, =ANATOP_BASE_ADDR
+    add   r3, r3, #PERIPBASE_VIRT
+
+    ldr     r2, =CCM_BASE_ADDR
+    add   r2, r2, #PERIPBASE_VIRT
+
+    ldr     r8, =MMDC_P0_BASE_ADDR
+    add   r8, r8, #PERIPBASE_VIRT
+
+
+    /* Prime all TLB entries. */
+    adr   r7, mx6sl_lpm_wfi               @Address in this function.
+
+    ldr     r6, [r7]
+
+    ldr     r6, [r8]
+    ldr     r6, [r3]
+    ldr     r6, [r2]
+    ldr     r6, [r1]
+
+     dsb
+
+     /* Disable Automatic power savings. */
+     ldr    r6, [r8, #0x404]
+     orr    r6, r6, #0x01
+     str    r6, [r8, #0x404]
+
+     /* Make the DDR explicitly enter self-refresh. */
+     ldr     r6, [r8, #0x404]
+     orr    r6, r6, #0x200000
+     str     r6, [r8, #0x404]
+
+poll_dvfs_set_1:
+     ldr     r6, [r8, #0x404]
+     and     r6, r6, #0x2000000
+     cmp    r6, #0x2000000
+     bne     poll_dvfs_set_1
+
+     /* Now set DDR rate to 1MHz. */
+     /* DDR is from bypassed PLL2 on periph2_clk2 path.
+       * Set the periph2_clk2_podf to divide by 8.
+       */
+     ldr    r6, [r2, #0x14]
+     orr   r6, r6, #0x07
+     str    r6, [r2, #0x14]
+
+     /* Now set MMDC PODF to divide by 3. */
+     ldr    r6, [r2, #0x14]
+     bic    r6, r6, #0x38
+     orr    r6, r6, #0x10
+     str     r6, [r2, #0x14]
+
+      /* Set the DDR IO in LPM state. */
+     sl_ddr_io_set_lpm
+
+     /* Set AHB to 8MHz., AXI to 3MHz */
+     /* We want to ensure IPG_PERCLK to AHB
+      * clk ratio is 1:2.5
+      */
+     /* Store the AXI/AHB podfs. */
+     ldr    r9, [r2, #0x14]
+     mov   r6, r9
+     bic      r6, r6, #0x1c00
+     orr    r6, r6, #0x800
+     orr    r6, r6, #0x70000
+     str     r6, [r2, #0x14]
+
+    /* Loop till podf is accepted. */
+ahb_podf:
+     ldr     r6, [r2, #0x48]
+     cmp   r6, #0x0
+     bne   podf_loop
+
+    /* Now set ARM to 24MHz. */
+    /* Move ARM to be sourced from STEP_CLK
+     * after setting STEP_CLK to 24MHz.
+     */
+     ldr    r6, [r2, #0xc]
+     bic   r6, r6, #0x100
+     str    r6, [r2, #0x0c]
+     /* Now PLL1_SW_CLK to step_clk. */
+     ldr    r6, [r2, #0x0c]
+     orr    r6, r6, #0x4
+     str    r6, [r2, #0x0c]
+
+    /* Bypass PLL1 and power it down. */
+    ldr     r6, =(1 << 16)
+    orr    r6, r6, #0x1000
+    str     r6, [r3, #0x04]
+
+    /* Set the ARM PODF to divide by 8. */
+    /* IPG is at 4MHz here, we need ARM to
+     * run at the 12:5 ratio (WAIT mode issue).
+     */
+    ldr    r6, =0x7
+    str    r6, [r2, #0x10]
+
+    /* Loop till podf is accepted. */
+podf_loop:
+     ldr     r6, [r2, #0x48]
+     cmp   r6, #0x0
+     bne   podf_loop
+
+     /* Now do WFI. */
+     dsb
+
+     wfi
+
+     /* Set original ARM PODF back. */
+    str    r0, [r2, #0x10]
+
+    /* Loop till podf is accepted. */
+podf_loop1:
+     ldr     r6, [r2, #0x48]
+     cmp   r6, #0x0
+     bne   podf_loop1
+
+     /* Power up PLL1 and un-bypass it. */
+    ldr     r6, =(1 << 12)
+    str     r6, [r3, #0x08]
+
+    /* Wait for PLL1 to relock. */
+wait_for_pll_lock:
+    ldr    r6, [r3, #0x0]
+    and   r6, r6, #0x80000000
+    cmp  r6, #0x80000000
+    bne   wait_for_pll_lock
+
+    ldr     r6, =(1 << 16)
+    str     r6, [r3, #0x08]
+
+    /* Set PLL1_sw_clk back to PLL1. */
+    ldr    r6, [r2, #0x0c]
+    bic    r6, r6, #0x4
+    str    r6, [r2, #0xc]
+
+    /* Restore AHB/AXI back. */
+    str      r9, [r2, #0x14]
+
+    /* Loop till podf is accepted. */
+ahb_podf1:
+     ldr     r6, [r2, #0x48]
+     cmp   r6, #0x0
+     bne   podf_loop1
+
+    mov        r9, r10                 /* get suspend_iram_base */
+     add       r9, r9, #IRAM_WAIT_SIZE /* 4K */
+
+    /* Restore the DDR IO before exiting self-refresh. */
+     sl_ddr_io_restore
+
+    /* Set MMDC back to 24MHz. */
+    /* Set periph2_clk2_podf to divide by 1. */
+     /* Now set MMDC PODF to divide by 1. */
+     ldr    r6, [r2, #0x14]
+     bic   r6, r6, #0x3f
+     str    r6, [r2, #0x14]
+
+     /* clear DVFS - exit from self refresh mode */
+     ldr     r6, [r8, #0x404]
+     bic     r6, r6, #0x200000
+     str     r6, [r8, #0x404]
+
+poll_dvfs_clear_1:
+     ldr     r6, [r8, #0x404]
+     and     r6, r6, #0x2000000
+     cmp     r6, #0x2000000
+     beq     poll_dvfs_clear_1
+
+     /* Enable Automatic power savings. */
+     ldr    r6, [r8, #0x404]
+     bic    r6, r6, #0x01
+     str    r6, [r8, #0x404]
+
+    pop {r4,r5, r6, r7, r8, r9, r10}
+
+    /* Restore registers */
+    mov     pc, lr
+
+    .type   mx6sl_do_wait, #object
+ENTRY(mx6sl_do_wait)
+    .word   mx6sl_wait
+    .size    mx6sl_wait, . - mx6sl_wait
index 57dee5f4c4c08300c4746a9418aacac41551d7b6..09940ffd49aaf66a382da645d1550c1efca778a4 100644 (file)
@@ -57,9 +57,10 @@ volatile unsigned int num_cpu_idle;
 volatile unsigned int num_cpu_idle_lock = 0x0;
 int wait_mode_arm_podf;
 int cur_arm_podf;
-bool arm_mem_clked_in_wait;
 void arch_idle_with_workaround(int cpu);
 
+extern void *mx6sl_wfi_iram_base;
+extern void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr);
 extern void mx6_wait(void *num_cpu_idle_lock, void *num_cpu_idle, \
                                int wait_arm_podf, int cur_arm_podf);
 extern bool enable_wait_mode;
@@ -78,6 +79,7 @@ void gpc_set_wakeup(unsigned int irq[4])
 
        return;
 }
+
 /* set cpu low power mode before WFI instruction */
 void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
 {
@@ -251,25 +253,34 @@ void arch_idle_single_core(void)
 
                ca9_do_idle();
        } else {
-               /*
-                 * Implement the 12:5 ARM:IPG_CLK ratio
-                 * workaround for the WAIT mode issue.
-                 * We can directly use the divider to drop the ARM
-                 * core freq in a single core environment.
-                 *  Set the ARM_PODF to get the max freq possible
-                 * to avoid the WAIT mode issue when IPG is at 66MHz.
-                 */
-               if (cpu_is_mx6sl()) {
-                       reg = __raw_readl(MXC_CCM_CGPR);
-                       reg |= MXC_CCM_CGPR_MEM_IPG_STOP_MASK;
-                       __raw_writel(reg, MXC_CCM_CGPR);
-               }
-               __raw_writel(wait_mode_arm_podf, MXC_CCM_CACRR);
-               while (__raw_readl(MXC_CCM_CDHIPR))
-                       ;
-               ca9_do_idle();
+               if (low_bus_freq_mode && cpu_is_mx6sl()) {
+                       u32 org_arm_podf = __raw_readl(MXC_CCM_CACRR);
 
-               __raw_writel(cur_arm_podf - 1, 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);
+
+                       /* Clear the chicken bit to allow memories
+                         * to be powered down
+                         */
+               } else {
+                       /*
+                         * Implement the 12:5 ARM:IPG_CLK ratio
+                         * workaround for the WAIT mode issue.
+                         * We can directly use the divider to drop the ARM
+                         * core freq in a single core environment.
+                         *  Set the ARM_PODF to get the max freq possible
+                         * to avoid the WAIT mode issue when IPG is at 66MHz.
+                         */
+                       __raw_writel(wait_mode_arm_podf, MXC_CCM_CACRR);
+                       while (__raw_readl(MXC_CCM_CDHIPR))
+                               ;
+                       ca9_do_idle();
+
+                       __raw_writel(cur_arm_podf - 1, MXC_CCM_CACRR);
+               }
        }
 }
 
@@ -331,7 +342,7 @@ void arch_idle(void)
 {
        if (enable_wait_mode) {
                mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
-               if ((mem_clk_on_in_wait || arm_mem_clked_in_wait)) {
+               if (mem_clk_on_in_wait) {
                        u32 reg;
                        /*
                          * MX6SL, MX6Q (TO1.2 or later) and