| /* |
| * Copyright (C) 2015 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. |
| */ |
| |
| #include <linux/linkage.h> |
| #include <asm/smp_scu.h> |
| #include "hardware.h" |
| |
| #define CCM_CBCDR 0x14 |
| #define CCM_CBCMR 0x18 |
| #define CCM_CSCMR1 0x1c |
| #define CCM_CDHIPR 0x48 |
| |
| .globl mx6q_lpddr2_freq_change_start |
| .globl mx6q_lpddr2_freq_change_end |
| |
| .macro switch_to_400MHz |
| |
| /* check if periph_clk_sel is already set. */ |
| ldr r9, [r2, #CCM_CBCDR] |
| and r9, r9, #(1 << 25) |
| cmp r9, #(1 << 25) |
| beq set_ahb_podf_before_switch1 |
| |
| /* change periph_clk to be sourced from pll3_clk. */ |
| ldr r9, [r2, #CCM_CBCMR] |
| bic r9, r9, #(3 << 12) |
| str r9, [r2, #CCM_CBCMR] |
| |
| ldr r9, [r2, #CCM_CBCDR] |
| bic r9, r9, #(0x38 << 24) |
| str r9, [r2, #CCM_CBCDR] |
| |
| /* now switch periph_clk to pll3_main_clk. */ |
| ldr r9, [r2, #CCM_CBCDR] |
| orr r9, r9, #(1 << 25) |
| str r9, [r2, #CCM_CBCDR] |
| |
| periph_clk_switch5: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne periph_clk_switch5 |
| |
| b switch_pre_periph_clk_400 |
| |
| set_ahb_podf_before_switch1: |
| /* |
| * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, |
| */ |
| ldr r9, [r2, #CCM_CBCDR] |
| ldr r6, =0x3f1f00 |
| bic r9, r9, r6 |
| orr r9, r9, #(0x9 << 8) |
| orr r9, r9, #(1 << 16) |
| str r9, [r2, #CCM_CBCDR] |
| |
| wait_div_update400_1: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne wait_div_update400_1 |
| |
| switch_pre_periph_clk_400: |
| |
| /* now switch pre_periph_clk to PFD_400MHz. */ |
| ldr r9, [r2, #CCM_CBCMR] |
| bic r9, r9, #(0xc << 16) |
| orr r9, r9, #(0x4 << 16) |
| str r9, [r2, #CCM_CBCMR] |
| |
| /* now switch periph_clk back. */ |
| ldr r9, [r2, #CCM_CBCDR] |
| bic r9, r9, #(1 << 25) |
| str r9, [r2, #CCM_CBCDR] |
| |
| periph_clk_switch6: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne periph_clk_switch6 |
| |
| .endm |
| |
| .macro switch_to_100MHz |
| /* check if periph_clk_sel is already set. */ |
| ldr r9, [r2, #CCM_CBCDR] |
| and r9, r9, #(1 << 25) |
| cmp r9, #(1 << 25) |
| beq switch_pre_periph_clk_100 |
| /* |
| * set the periph_clk to be sourced from PLL2_PFD_200M |
| * change periph_clk to be sourced from pll3_clk. |
| * ensure PLL3 is the source and set the divider to 1. |
| */ |
| ldr r9, [r2, #CCM_CBCMR] |
| bic r9, r9, #(0x3 << 12) |
| str r9, [r2, #CCM_CBCMR] |
| |
| ldr r9, [r2, #CCM_CBCDR] |
| bic r9, r9, #(0x38 << 24) |
| str r9, [r2, #CCM_CBCDR] |
| |
| /* now switch periph_clk to pll3_main_clk. */ |
| ldr r9, [r2, #CCM_CBCDR] |
| orr r9, r9, #(1 << 25) |
| str r9, [r2, #CCM_CBCDR] |
| |
| periph_clk_switch_100: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne periph_clk_switch_100 |
| |
| switch_pre_periph_clk_100: |
| /* now switch pre_periph_clk to PFD_200MHz. */ |
| ldr r9, [r2, #CCM_CBCMR] |
| orr r9, r9, #(0xc << 16) |
| str r9, [r2, #CCM_CBCMR] |
| |
| /* set the MMDC_DIV=2, AXI_DIV=4, AHB_DIV=8 */ |
| ldr r9, [r2, #CCM_CBCDR] |
| ldr r6, =0x3f1f00 |
| bic r9, r9, r6 |
| orr r9, r9, #(0x8 << 16) |
| orr r9, r9, #(0x3 << 16) |
| |
| /* |
| * if changing AHB divider remember to change |
| * the IPGPER divider too below. |
| */ |
| orr r9, r9, #0x1d00 |
| str r9, [r2, #CCM_CBCDR] |
| |
| wait_div_update_100: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne wait_div_update_100 |
| |
| /* now switch periph_clk back. */ |
| ldr r9, [r2, #CCM_CBCDR] |
| bic r9, r9, #(1 << 25) |
| str r9, [r2, #CCM_CBCDR] |
| |
| periph_clk_switch2: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne periph_clk_switch2 |
| |
| .endm |
| |
| .macro switch_to_24MHz |
| /* |
| * change the freq now try setting DDR to 24MHz. |
| * source it from the periph_clk2 ensure the |
| * periph_clk2 is sourced from 24MHz and the |
| * divider is 1. |
| */ |
| |
| ldr r9, [r2, #CCM_CBCMR] |
| bic r9, r9, #(0x3 << 12) |
| orr r9, r9, #(1 << 12) |
| str r9, [r2, #CCM_CBCMR] |
| |
| ldr r9, [r2, #CCM_CBCDR] |
| bic r9, r9, #(0x38 << 24) |
| str r9, [r2, #CCM_CBCDR] |
| |
| /* now switch periph_clk to 24MHz. */ |
| ldr r9, [r2, #CCM_CBCDR] |
| orr r9, r9, #(1 << 25) |
| str r9, [r2, #CCM_CBCDR] |
| |
| periph_clk_switch1: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne periph_clk_switch1 |
| |
| /* change all the dividers to 1. */ |
| ldr r9, [r2, #CCM_CBCDR] |
| ldr r6, =0x3f1f00 |
| bic r9, r9, r6 |
| orr r9, r9, #(1 << 8) |
| str r9, [r2, #CCM_CBCDR] |
| |
| /* Wait for the divider to change. */ |
| wait_div_update: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne wait_div_update |
| |
| .endm |
| |
| .macro switch_to_24MHZ_from_pll2 |
| /* Change DDR freq settings from pll2_pfd2 (div 2) */ |
| |
| ldr r9, [r2, #CCM_CBCMR] |
| bic r9, r9, #(0x3 << 18) |
| orr r9, r9, #(0x3 << 18) |
| str r9, [r2, #CCM_CBCMR] |
| |
| ldr r9, [r2, #CCM_CBCDR] |
| bic r9, r9, #(1 << 25) |
| str r9, [r2, #CCM_CBCDR] |
| |
| periph_clk_switch_pll2_pfd2: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne periph_clk_switch_pll2_pfd2 |
| |
| ldr r9, [r2, #CCM_CBCDR] |
| ldr r6, =0x3f1f00 |
| bic r9, r9, r6 |
| orr r9, r9, #(1 << 8) |
| orr r9, r9, #(0x7 << 19) |
| str r9, [r2, #CCM_CBCDR] |
| |
| wait_div_update2: |
| ldr r9, [r2, #CCM_CDHIPR] |
| cmp r9, #0 |
| bne wait_div_update2 |
| |
| .endm |
| |
| .macro set_timings_below_100MHz_operation |
| /* Set MMDCx_MISC[RALAT] = 2 cycles */ |
| ldr r6, [r8, #0x18] |
| bic r6, r6, #(0x7 << 6) |
| orr r6, r6, #(0x2 << 6) |
| str r6, [r8, #0x18] |
| |
| /* Adjust LPDDR2 timmings for 24Mhz operation */ |
| ldr r5, =0x03032073 |
| str r5, [r8, #0xC] /* MMDC0_MDCFG0 */ |
| ldr r7, =0x00020482 |
| str r7, [r8, #0x10] /* MMDC0_MDCFG1 */ |
| ldr r9, =0x00000049 |
| str r9, [r8, #0x14] /* MMDC0_MDCFG2 */ |
| ldr r10, =0x00020333 |
| str r10, [r8, #0x38] /* MMDC0_MDCFG3LP */ |
| |
| /* Check if lpddr2 channel 1 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_below_100Mhz_ch1_timings |
| |
| ldr r6, [r4, #0x18] |
| bic r6, r6, #(0x7 << 6) |
| orr r6, r6, #(0x2 << 6) |
| str r6, [r4, #0x18] |
| |
| str r5, [r4, #0xC] /* MMDC1_MDCFG0 */ |
| str r7, [r4, #0x10] /* MMDC1_MDCFG1 */ |
| str r9, [r4, #0x14] /* MMDC1_MDCFG2 */ |
| str r10, [r4, #0x38] /* MMDC1_MDCFG3LP */ |
| |
| skip_below_100Mhz_ch1_timings: |
| |
| .endm |
| |
| .macro set_timmings_above_100MHz_operation |
| /* Set MMDCx_MISC[RALAT] = 5 cycles */ |
| ldr r6, [r8, #0x18] |
| bic r6, r6, #(0x7 << 6) |
| orr r6, r6, #(0x5 << 6) |
| str r6, [r8, #0x18] |
| |
| /* Adjust LPDDR2 timmings for 400Mhz operation */ |
| ldr r5, =0x33374133 |
| str r5, [r8, #0xC] /* MMDC0_MDCFG0 */ |
| ldr r7, =0x00100A82 |
| str r7, [r8, #0x10] /* MMDC0_MDCFG1 */ |
| ldr r9, =0x00000093 |
| str r9, [r8, #0x14] /* MMDC0_MDCFG2 */ |
| ldr r10, =0x001A0889 |
| str r10, [r8, #0x38] /* MMDC0_MDCFG3LP */ |
| |
| /* Check if lpddr2 channel 1 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_above_100Mhz_ch1_timings |
| |
| ldr r6, [r4, #0x18] |
| bic r6, r6, #(0x7 << 6) |
| orr r6, r6, #(0x5 << 6) |
| str r6, [r4, #0x18] |
| |
| str r5, [r4, #0xC] /* MMDC1_MDCFG0 */ |
| str r7, [r4, #0x10] /* MMDC1_MDCFG1 */ |
| str r9, [r4, #0x14] /* MMDC1_MDCFG2 */ |
| str r10, [r4, #0x38] /* MMDC1_MDCFG3LP */ |
| |
| skip_above_100Mhz_ch1_timings: |
| |
| .endm |
| |
| .macro mmdc_clk_lower_100MHz |
| |
| set_timings_below_100MHz_operation |
| /* |
| * 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 r9, =0x3FF |
| and r6, r6, r9 |
| /* 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 r9, =0x3FF |
| bic r6, r6, r9 |
| 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 |
| |
| /* Check if lpddr2 channel 2 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_lower_force_measure_ch1 |
| |
| ldr r5, =0x8B8 |
| ldr r6, [r4, r5] |
| /* Original MU unit count */ |
| mov r6, r6, LSR #16 |
| ldr r9, =0x3FF |
| and r6, r6, r9 |
| /* 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, [r4, r5] |
| orr r6, r6, #0x400 |
| str r6, [r4, 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, [r4, r5] |
| ldr r9, =0x3FF |
| bic r6, r6, r9 |
| orr r6, r6, r7 |
| str r6, [r4, r5] |
| /* Now perform a Force Measurement. */ |
| ldr r6, [r4, r5] |
| orr r6, r6, #0x800 |
| str r6, [r4, r5] |
| /* Wait for FRC_MSR to clear. */ |
| force_measure_ch1: |
| ldr r6, [r4, r5] |
| and r6, r6, #0x800 |
| cmp r6, #0x0 |
| bne force_measure_ch1 |
| |
| skip_lower_force_measure_ch1: |
| |
| .endm |
| |
| .macro mmdc_clk_above_100MHz |
| |
| set_timmings_above_100MHz_operation |
| |
| /* 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 |
| |
| /* Check if lpddr2 channel 2 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_above_force_measure_ch1 |
| |
| ldr r5, =0x8B8 |
| ldr r6, [r4, r5] |
| bic r6, r6, #0x400 |
| str r6, [r4, r5] |
| /* Now perform a Force Measurement. */ |
| ldr r6, [r4, r5] |
| orr r6, r6, #0x800 |
| str r6, [r4, r5] |
| /* Wait for FRC_MSR to clear. */ |
| force_measure1_ch1: |
| ldr r6, [r4, r5] |
| and r6, r6, #0x800 |
| cmp r6, #0x0 |
| bne force_measure1_ch1 |
| |
| skip_above_force_measure_ch1: |
| |
| .endm |
| |
| /* |
| * mx6_lpddr2_freq_change |
| * |
| * Make sure DDR is in self-refresh. |
| * IRQs are already disabled. |
| * r0 : DDR freq. |
| * r1: low_bus_freq_mode flag |
| */ |
| .align 3 |
| ENTRY(mx6q_lpddr2_freq_change) |
| mx6q_lpddr2_freq_change_start: |
| push {r2-r10} |
| |
| /* |
| * To ensure no page table walks occur in DDR, we |
| * have a another page table stored in IRAM that only |
| * contains entries pointing to IRAM, AIPS1 and AIPS2. |
| * We need to set the TTBR1 to the new IRAM TLB. |
| * Do the following steps: |
| * 1. Flush the Branch Target Address Cache (BTAC) |
| * 2. Set TTBR1 to point to IRAM page table. |
| * 3. Disable page table walks in TTBR0 (PD0 = 1) |
| * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 |
| * and 2-4G is translated by TTBR1. |
| */ |
| |
| ldr r6, =iram_tlb_phys_addr |
| ldr r7, [r6] |
| |
| /* Flush the Branch Target Address Cache (BTAC) */ |
| ldr r6, =0x0 |
| mcr p15, 0, r6, c7, c1, 6 |
| |
| /* Disable Branch Prediction, Z bit in SCTLR. */ |
| mrc p15, 0, r6, c1, c0, 0 |
| bic r6, r6, #0x800 |
| mcr p15, 0, r6, c1, c0, 0 |
| |
| dsb |
| isb |
| /* Store the IRAM table in TTBR1 */ |
| mcr p15, 0, r7, c2, c0, 1 |
| |
| /* Read TTBCR and set PD0=1, N = 1 */ |
| mrc p15, 0, r6, c2, c0, 2 |
| orr r6, r6, #0x11 |
| mcr p15, 0, r6, c2, c0, 2 |
| |
| dsb |
| isb |
| |
| /* flush the TLB */ |
| ldr r6, =0x0 |
| mcr p15, 0, r6, c8, c3, 0 |
| |
| /* Disable L1 data cache. */ |
| mrc p15, 0, r6, c1, c0, 0 |
| bic r6, r6, #0x4 |
| mcr p15, 0, r6, c1, c0, 0 |
| |
| dsb |
| isb |
| |
| #ifdef CONFIG_CACHE_L2X0 |
| /* |
| * Need to make sure the buffers in L2 are drained. |
| * Performing a sync operation does this. |
| */ |
| ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) |
| |
| /* Wait for background operations to complete. */ |
| wait_for_l2_to_idle: |
| ldr r6, [r7, #0x730] |
| cmp r6, #0x0 |
| bne wait_for_l2_to_idle |
| |
| mov r6, #0x0 |
| str r6, [r7, #0x730] |
| |
| /* |
| * The second dsb might be needed to keep cache sync (device write) |
| * ordering with the memory accesses before it. |
| */ |
| dsb |
| isb |
| |
| /* Disable L2. */ |
| str r6, [r7, #0x100] |
| #endif |
| |
| ldr r3, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) |
| ldr r2, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) |
| ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) |
| ldr r4, =IMX_IO_P2V(MX6Q_MMDC_P1_BASE_ADDR) |
| |
| /* Disable Automatic power savings. */ |
| ldr r6, [r8, #0x404] |
| orr r6, r6, #0x01 |
| str r6, [r8, #0x404] |
| |
| /* MMDC0_MDPDC disable power down timer */ |
| ldr r6, [r8, #0x4] |
| bic r6, r6, #0xff00 |
| str r6, [r8, #0x4] |
| |
| /* Check if lpddr2 channel 2 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_psd_ch1 |
| |
| ldr r6, [r4, #0x404] |
| orr r6, r6, #0x01 |
| str r6, [r4, #0x404] |
| |
| ldr r6, [r4, #0x4] |
| bic r6, r6, #0xff00 |
| str r6, [r4, #0x4] |
| |
| skip_psd_ch1: |
| /* Delay for a while */ |
| ldr r10, =10 |
| delay1: |
| ldr r7, =0 |
| cont1: |
| ldr r6, [r8, r7] |
| add r7, r7, #4 |
| cmp r7, #16 |
| bne cont1 |
| sub r10, r10, #1 |
| cmp r10, #0 |
| bgt delay1 |
| |
| /* 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 |
| |
| /* set SBS step-by-step mode */ |
| ldr r6, [r8, #0x410] |
| orr r6, r6, #0x100 |
| str r6, [r8, #0x410] |
| |
| /* Check if lpddr2 channel 2 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_sbs_ch1 |
| |
| ldr r6, [r4, #0x404] |
| orr r6, r6, #0x200000 |
| str r6, [r4, #0x404] |
| |
| poll_dvfs_set_2: |
| ldr r6, [r4, #0x404] |
| and r6, r6, #0x2000000 |
| cmp r6, #0x2000000 |
| bne poll_dvfs_set_2 |
| |
| ldr r6, [r4, #0x410] |
| orr r6, r6, #0x100 |
| str r6, [r4, #0x410] |
| |
| skip_sbs_ch1: |
| 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 |
| |
| ldr r10, =100000000 |
| cmp r0, r10 |
| beq set_to_100MHz |
| |
| ldr r10, =400000000 |
| cmp r0, r10 |
| switch_to_400MHz |
| b done |
| |
| set_to_24MHz: |
| /* |
| switch_to_24MHZ_from_pll2 |
| */ |
| switch_to_24MHz |
| b done |
| |
| set_to_100MHz: |
| switch_to_100MHz |
| |
| done: |
| |
| ldr r10,=100000000 |
| cmp r0, r10 |
| blt skip_mmdc_clk_check |
| mmdc_clk_above_100MHz |
| |
| skip_mmdc_clk_check: |
| |
| /* 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] |
| |
| /* Check if lpddr2 channel 2 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_enable_psd_ch1 |
| |
| ldr r6, [r4, #0x404] |
| bic r6, r6, #0x200000 |
| str r6, [r4, #0x404] |
| |
| poll_dvfs_clear_2: |
| ldr r6, [r4, #0x404] |
| and r6, r6, #0x2000000 |
| cmp r6, #0x2000000 |
| beq poll_dvfs_clear_2 |
| |
| ldr r6, [r4, #0x404] |
| bic r6, r6, #0x01 |
| str r6, [r4, #0x404] |
| |
| skip_enable_psd_ch1: |
| ldr r10, =24000000 |
| cmp r0, r10 |
| beq skip_power_down |
| |
| /* Enable MMDC power down timer. */ |
| ldr r6, [r8, #0x4] |
| orr r6, r6, #0x5500 |
| str r6, [r8, #0x4] |
| |
| /* Check if lpddr2 channel 2 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_power_down |
| |
| ldr r6, [r4, #0x4] |
| orr r6, r6, #0x5500 |
| str r6, [r4, #0x4] |
| |
| skip_power_down: |
| /* clear SBS - unblock DDR accesses */ |
| ldr r6, [r8, #0x410] |
| bic r6, r6, #0x100 |
| str r6, [r8, #0x410] |
| |
| /* Check if lpddr2 channel 2 is enabled */ |
| ldr r6, [r8, #0x18] |
| ands r6, r6, #(1 << 2) |
| beq skip_disable_sbs_ch1 |
| |
| ldr r6, [r4, #0x410] |
| bic r6, r6, #0x100 |
| str r6, [r4, #0x410] |
| |
| skip_disable_sbs_ch1: |
| #ifdef CONFIG_CACHE_L2X0 |
| /* Enable L2. */ |
| ldr r7, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) |
| ldr r6, =0x1 |
| str r6, [r7, #0x100] |
| #endif |
| |
| /* Enable L1 data cache. */ |
| mrc p15, 0, r6, c1, c0, 0 |
| orr r6, r6, #0x4 |
| mcr p15, 0, r6, c1, c0, 0 |
| |
| /* Restore the TTBCR */ |
| dsb |
| isb |
| |
| /* Read TTBCR and set PD0=0, N = 0 */ |
| mrc p15, 0, r6, c2, c0, 2 |
| bic r6, r6, #0x11 |
| mcr p15, 0, r6, c2, c0, 2 |
| dsb |
| isb |
| |
| /* flush the TLB */ |
| ldr r6, =0x0 |
| mcr p15, 0, r6, c8, c3, 0 |
| |
| dsb |
| isb |
| |
| /* Enable Branch Prediction, Z bit in SCTLR. */ |
| mrc p15, 0, r6, c1, c0, 0 |
| orr r6, r6, #0x800 |
| mcr p15, 0, r6, c1, c0, 0 |
| |
| /* Flush the Branch Target Address Cache (BTAC) */ |
| ldr r6, =0x0 |
| mcr p15, 0, r6, c7, c1, 6 |
| |
| nop |
| nop |
| nop |
| nop |
| nop |
| |
| nop |
| nop |
| nop |
| nop |
| nop |
| |
| nop |
| nop |
| nop |
| nop |
| nop |
| |
| nop |
| nop |
| nop |
| nop |
| nop |
| |
| nop |
| nop |
| nop |
| nop |
| nop |
| |
| pop {r2-r10} |
| |
| /* Restore registers */ |
| mov pc, lr |
| |
| /* |
| * Add ltorg here to ensure that all |
| * literals are stored here and are |
| * within the text space. |
| */ |
| .ltorg |
| mx6q_lpddr2_freq_change_end: |