blob: 80fb1184fa547a8861499f68e316d28661f1d740 [file] [log] [blame]
/*
* Copyright (C) 2015-2016 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 "hardware.h"
#define DDRC_MSTR 0x0
#define DDRC_STAT 0x4
#define DDRC_PWRCTL 0x30
#define DDRC_RFSHTMG 0x64
#define DDRC_DBG1 0x304
#define DDRC_PSTAT 0x3fc
#define DDRC_PCTRL_0 0x490
#define DDRC_DFIMISC 0x1b0
#define DDRC_DBGCAM 0x308
#define DDRC_SWCTL 0x320
#define DDRC_SWSTAT 0x324
#define DDRPHY_LP_CON0 0x18
#define IOMUXC_GPR8 0x20
#define DDRPHY_PHY_CON1 0x4
#define DDRPHY_MDLL_CON0 0xb0
#define DDRPHY_MDLL_CON1 0xb4
#define DDRPHY_OFFSETD_CON0 0x50
#define DDRPHY_OFFSETR_CON0 0x20
#define DDRPHY_OFFSETR_CON1 0x24
#define DDRPHY_OFFSETR_CON2 0x28
#define DDRPHY_OFFSETW_CON0 0x30
#define DDRPHY_OFFSETW_CON1 0x34
#define DDRPHY_OFFSETW_CON2 0x38
#define DDRPHY_RFSHTMG 0x64
#define DDRPHY_CA_WLDSKEW_CON0 0x6c
#define DDRPHY_CA_DSKEW_CON0 0x7c
#define DDRPHY_CA_DSKEW_CON1 0x80
#define DDRPHY_CA_DSKEW_CON2 0x84
#define ANADIG_DIGPROG 0x800
.align 3
.macro ddrc_prepare
/* disable port */
ldr r7, =0x0
str r7, [r4, #DDRC_PCTRL_0]
/* wait port busy done */
ldr r6, =0x10001
1:
ldr r7, [r4, #DDRC_PSTAT]
and r7, r7, r6
cmp r7, #0
bne 1b
ldr r7, =0x20
str r7, [r4, #DDRC_PWRCTL]
ldr r6, =0x23
2:
ldr r7, [r4, #DDRC_STAT]
and r7, r7, r6
cmp r7, r6
bne 2b
ldr r7, =0x1
str r7, [r4, #DDRC_DBG1]
ldr r6, =0x30000000
3:
ldr r7, [r4, #DDRC_DBGCAM]
and r7, r7, r6
cmp r7, r6
bne 3b
ldr r7, =0x0
str r7, [r4, #DDRC_SWCTL]
ldr r7, =0x0
str r7, [r4, #DDRC_DFIMISC]
ldr r7, =0x1
str r7, [r4, #DDRC_SWCTL]
ldr r6, =0x1
4:
ldr r7, [r4, #DDRC_SWSTAT]
and r7, r7, r6
cmp r7, r6
bne 4b
.endm
.macro ddrc_done
ldr r7, =0x0
str r7, [r4, #DDRC_PWRCTL]
ldr r6, =0x3
5:
ldr r7, [r4, #DDRC_STAT]
and r7, r7, r6
cmp r7, r6
beq 5b
ldr r7, =0x0
str r7, [r4, #DDRC_DBG1]
ldr r7, =0x1
str r7, [r4, #DDRC_PCTRL_0]
/* enable auto self-refresh */
ldr r7, [r4, #DDRC_PWRCTL]
orr r7, r7, #(1 << 0)
str r7, [r4, #DDRC_PWRCTL]
.endm
.macro switch_to_below_100m
/* LPDDR2 and LPDDR3 has different setting */
ldr r8, [r4, #DDRC_MSTR]
ands r8, r8, #0x4
bne 9f
/* LPDDR3 */
ldr r7, =0x00000100
str r7, [r5, #DDRPHY_PHY_CON1]
b 10f
9:
/* LPDDR2 */
ldr r7, =0x10010100
str r7, [r5, #DDRPHY_PHY_CON1]
10:
ldr r6, =24000000
cmp r0, r6
beq 16f
ldr r7, =0x0005000B
str r7, [r4, #DDRC_RFSHTMG]
b 6f
16:
ldr r7, =0x00010003
str r7, [r4, #DDRC_RFSHTMG]
/* dram alt sel set to OSC */
ldr r7, =0x10000000
ldr r8, =0xa080
str r7, [r2, r8]
/* dram root set to from dram alt, div by 1 */
ldr r7, =0x11000000
ldr r8, =0x9880
str r7, [r2, r8]
b 7f
6:
/* dram alt sel set to pfd0_392m */
ldr r7, =0x15000000
ldr r8, =0xa080
str r7, [r2, r8]
/* dram root set to from dram alt, div by 4 */
ldr r7, =0x11000003
ldr r8, =0x9880
str r7, [r2, r8]
7:
ldr r7, =0x202ffd0
str r7, [r5, #DDRPHY_MDLL_CON0]
ldr r7, =0x7f
str r7, [r5, #DDRPHY_OFFSETD_CON0]
ldr r7, =0x7f7f7f7f
str r7, [r5, #DDRPHY_OFFSETR_CON0]
str r7, [r5, #DDRPHY_OFFSETR_CON1]
ldr r7, =0x7f
str r7, [r5, #DDRPHY_OFFSETR_CON2]
ldr r7, =0x7f7f7f7f
str r7, [r5, #DDRPHY_OFFSETW_CON0]
str r7, [r5, #DDRPHY_OFFSETW_CON1]
ldr r7, =0x7f
str r7, [r5, #DDRPHY_OFFSETW_CON2]
ldr r7, [r9, #ANADIG_DIGPROG]
and r7, r7, #0x11
cmp r7, #0x11
bne 11f
ldr r7, =0x0
str r7, [r5, #DDRPHY_CA_WLDSKEW_CON0]
ldr r7, =0x60606060
str r7, [r5, #DDRPHY_CA_DSKEW_CON0]
str r7, [r5, #DDRPHY_CA_DSKEW_CON1]
ldr r7, =0x00006060
str r7, [r5, #DDRPHY_CA_DSKEW_CON2]
b 12f
11:
ldr r7, =0x0
str r7, [r5, #DDRPHY_CA_DSKEW_CON0]
str r7, [r5, #DDRPHY_CA_DSKEW_CON1]
str r7, [r5, #DDRPHY_CA_DSKEW_CON2]
12:
ldr r7, =0x100007f
str r7, [r5, #DDRPHY_OFFSETD_CON0]
ldr r7, =0x7f
str r7, [r5, #DDRPHY_OFFSETD_CON0]
.endm
.macro switch_to_533m
ldr r7, =0x10210100
str r7, [r5, #DDRPHY_PHY_CON1]
ldr r7, =0x00200038
str r7, [r4, #DDRC_RFSHTMG]
/* dram root set to from dram main, div by 2 */
ldr r7, =0x10000001
ldr r8, =0x9880
str r7, [r2, r8]
ldr r7, =0x1010007e
str r7, [r5, #DDRPHY_MDLL_CON0]
ldr r7, =0x10000008
str r7, [r5, #DDRPHY_OFFSETD_CON0]
ldr r7, =0x08080808
str r7, [r5, #DDRPHY_OFFSETR_CON0]
str r7, [r5, #DDRPHY_OFFSETR_CON1]
ldr r7, =0x8
str r7, [r5, #DDRPHY_OFFSETR_CON2]
ldr r7, =0x08080808
str r7, [r5, #DDRPHY_OFFSETW_CON0]
str r7, [r5, #DDRPHY_OFFSETW_CON1]
ldr r7, =0x8
str r7, [r5, #DDRPHY_OFFSETW_CON2]
/* LPDDR2 and LPDDR3 has different setting */
ldr r8, [r4, #DDRC_MSTR]
ands r8, r8, #0x4
beq 15f
ldr r7, [r9, #ANADIG_DIGPROG]
and r7, r7, #0x11
cmp r7, #0x11
bne 14f
ldr r7, =0x08080808
str r7, [r5, #DDRPHY_CA_DSKEW_CON0]
str r7, [r5, #DDRPHY_CA_DSKEW_CON1]
ldr r7, =0x0a0a0808
str r7, [r5, #DDRPHY_CA_DSKEW_CON2]
ldr r7, =0x0a0a0a0a
str r7, [r5, #DDRPHY_CA_WLDSKEW_CON0]
b 14f
15:
ldr r7, [r9, #ANADIG_DIGPROG]
and r7, r7, #0x11
cmp r7, #0x11
bne 13f
ldr r7, =0x1c1c1c1c
str r7, [r5, #DDRPHY_CA_DSKEW_CON0]
str r7, [r5, #DDRPHY_CA_DSKEW_CON1]
ldr r7, =0x30301c1c
str r7, [r5, #DDRPHY_CA_DSKEW_CON2]
ldr r7, =0x30303030
str r7, [r5, #DDRPHY_CA_WLDSKEW_CON0]
b 14f
13:
ldr r7, =0x08080808
str r7, [r5, #DDRPHY_CA_DSKEW_CON0]
str r7, [r5, #DDRPHY_CA_DSKEW_CON1]
ldr r7, =0x0808
str r7, [r5, #DDRPHY_CA_DSKEW_CON2]
14:
ldr r7, =0x11000008
str r7, [r5, #DDRPHY_OFFSETD_CON0]
ldr r7, =0x10000008
str r7, [r5, #DDRPHY_OFFSETD_CON0]
ldr r6, =0x4
8:
ldr r7, [r5, #DDRPHY_MDLL_CON1]
and r7, r7, r6
cmp r7, r6
bne 8b
.endm
ENTRY(imx_lpddr3_freq_change)
push {r2 - r9}
/*
* 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
ldr r2, =IMX_IO_P2V(MX7D_CCM_BASE_ADDR)
ldr r3, =IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR)
ldr r4, =IMX_IO_P2V(MX7D_DDRC_BASE_ADDR)
ldr r5, =IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR)
ldr r9, =IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR)
ddrc_prepare
ldr r6, =100000000
cmp r0, r6
bgt set_to_533m
set_to_below_100m:
switch_to_below_100m
b done
set_to_533m:
switch_to_533m
b done
done:
ddrc_done
/* 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
/* Restore registers */
pop {r2 - r9}
mov pc, lr
ENDPROC(imx_lpddr3_freq_change)