1*53c45f0cShuang lin /* 2*53c45f0cShuang lin * (C) Copyright 2015 Google, Inc 3*53c45f0cShuang lin * 4*53c45f0cShuang lin * SPDX-License-Identifier: GPL-2.0+ 5*53c45f0cShuang lin */ 6*53c45f0cShuang lin #include <common.h> 7*53c45f0cShuang lin #include <asm/io.h> 8*53c45f0cShuang lin #include <asm/types.h> 9*53c45f0cShuang lin #include <asm/arch/cru_rk3036.h> 10*53c45f0cShuang lin #include <asm/arch/grf_rk3036.h> 11*53c45f0cShuang lin #include <asm/arch/hardware.h> 12*53c45f0cShuang lin #include <asm/arch/sdram_rk3036.h> 13*53c45f0cShuang lin #include <asm/arch/timer.h> 14*53c45f0cShuang lin #include <asm/arch/uart.h> 15*53c45f0cShuang lin 16*53c45f0cShuang lin /* 17*53c45f0cShuang lin * we can not fit the code to access the device tree in SPL 18*53c45f0cShuang lin * (due to 4K SRAM size limits), so these are hard-coded 19*53c45f0cShuang lin */ 20*53c45f0cShuang lin #define CRU_BASE 0x20000000 21*53c45f0cShuang lin #define GRF_BASE 0x20008000 22*53c45f0cShuang lin #define DDR_PHY_BASE 0x2000a000 23*53c45f0cShuang lin #define DDR_PCTL_BASE 0x20004000 24*53c45f0cShuang lin #define CPU_AXI_BUS_BASE 0x10128000 25*53c45f0cShuang lin 26*53c45f0cShuang lin struct rk3036_sdram_priv { 27*53c45f0cShuang lin struct rk3036_cru *cru; 28*53c45f0cShuang lin struct rk3036_grf *grf; 29*53c45f0cShuang lin struct rk3036_ddr_phy *phy; 30*53c45f0cShuang lin struct rk3036_ddr_pctl *pctl; 31*53c45f0cShuang lin struct rk3036_service_sys *axi_bus; 32*53c45f0cShuang lin 33*53c45f0cShuang lin /* ddr die config */ 34*53c45f0cShuang lin struct rk3036_ddr_config ddr_config; 35*53c45f0cShuang lin }; 36*53c45f0cShuang lin 37*53c45f0cShuang lin /* use integer mode, 396MHz dpll setting 38*53c45f0cShuang lin * refdiv, fbdiv, postdiv1, postdiv2 39*53c45f0cShuang lin */ 40*53c45f0cShuang lin const struct pll_div dpll_init_cfg = {1, 66, 4, 1}; 41*53c45f0cShuang lin 42*53c45f0cShuang lin /* 396Mhz ddr timing */ 43*53c45f0cShuang lin const struct rk3036_ddr_timing ddr_timing = {0x18c, 44*53c45f0cShuang lin {0x18c, 0xc8, 0x1f4, 0x27, 0x4e, 45*53c45f0cShuang lin 0x4, 0x8b, 0x06, 0x03, 0x0, 0x06, 0x05, 0x0f, 0x15, 0x06, 0x04, 0x04, 46*53c45f0cShuang lin 0x06, 0x04, 0x200, 0x03, 0x0a, 0x40, 0x2710, 0x01, 0x05, 0x05, 0x03, 47*53c45f0cShuang lin 0x0c, 0x28, 0x100, 0x0, 0x04, 0x0}, 48*53c45f0cShuang lin {{0x420, 0x42, 0x0, 0x0}, 0x01, 0x60}, 49*53c45f0cShuang lin {0x24717315} }; 50*53c45f0cShuang lin 51*53c45f0cShuang lin /* 52*53c45f0cShuang lin * [7:6] bank(n:n bit bank) 53*53c45f0cShuang lin * [5:4] row(13+n) 54*53c45f0cShuang lin * [3] cs(0:1 cs, 1:2 cs) 55*53c45f0cShuang lin * [2:1] bank(n:n bit bank) 56*53c45f0cShuang lin * [0] col(10+n) 57*53c45f0cShuang lin */ 58*53c45f0cShuang lin const char ddr_cfg_2_rbc[] = { 59*53c45f0cShuang lin ((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 1), 60*53c45f0cShuang lin ((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 0), 61*53c45f0cShuang lin ((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 0), 62*53c45f0cShuang lin ((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 0), 63*53c45f0cShuang lin ((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 1), 64*53c45f0cShuang lin ((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 1), 65*53c45f0cShuang lin ((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 1), 66*53c45f0cShuang lin ((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 0), 67*53c45f0cShuang lin ((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 1), 68*53c45f0cShuang lin ((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 0), 69*53c45f0cShuang lin ((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 1), 70*53c45f0cShuang lin ((1 << 6) | (2 << 4) | (0 << 3) | (2 << 1) | 0), 71*53c45f0cShuang lin ((3 << 6) | (2 << 4) | (0 << 3) | (0 << 1) | 1), 72*53c45f0cShuang lin ((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 0), 73*53c45f0cShuang lin }; 74*53c45f0cShuang lin 75*53c45f0cShuang lin /* DDRPHY REG */ 76*53c45f0cShuang lin enum { 77*53c45f0cShuang lin /* DDRPHY_REG1 */ 78*53c45f0cShuang lin SOFT_RESET_MASK = 3, 79*53c45f0cShuang lin SOFT_RESET_SHIFT = 2, 80*53c45f0cShuang lin 81*53c45f0cShuang lin /* DDRPHY_REG2 */ 82*53c45f0cShuang lin MEMORY_SELECT_DDR3 = 0 << 6, 83*53c45f0cShuang lin DQS_SQU_CAL_NORMAL_MODE = 0 << 1, 84*53c45f0cShuang lin DQS_SQU_CAL_START = 1 << 0, 85*53c45f0cShuang lin DQS_SQU_NO_CAL = 0 << 0, 86*53c45f0cShuang lin 87*53c45f0cShuang lin /* DDRPHY_REG2A */ 88*53c45f0cShuang lin CMD_DLL_BYPASS = 1 << 4, 89*53c45f0cShuang lin CMD_DLL_BYPASS_DISABLE = 0 << 4, 90*53c45f0cShuang lin HIGH_8BIT_DLL_BYPASS = 1 << 3, 91*53c45f0cShuang lin HIGH_8BIT_DLL_BYPASS_DISABLE = 0 << 3, 92*53c45f0cShuang lin LOW_8BIT_DLL_BYPASS = 1 << 2, 93*53c45f0cShuang lin LOW_8BIT_DLL_BYPASS_DISABLE = 0 << 2, 94*53c45f0cShuang lin 95*53c45f0cShuang lin /* DDRPHY_REG19 */ 96*53c45f0cShuang lin CMD_FEEDBACK_ENABLE = 1 << 5, 97*53c45f0cShuang lin CMD_SLAVE_DLL_INVERSE_MODE = 1 << 4, 98*53c45f0cShuang lin CMD_SLAVE_DLL_NO_INVERSE_MODE = 0 << 4, 99*53c45f0cShuang lin CMD_SLAVE_DLL_ENALBE = 1 << 3, 100*53c45f0cShuang lin CMD_TX_SLAVE_DLL_DELAY_MASK = 7, 101*53c45f0cShuang lin CMD_TX_SLAVE_DLL_DELAY_SHIFT = 0, 102*53c45f0cShuang lin 103*53c45f0cShuang lin /* DDRPHY_REG6 */ 104*53c45f0cShuang lin LEFT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4, 105*53c45f0cShuang lin LEFT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4, 106*53c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_ENABLE = 1 << 3, 107*53c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_MASK = 7, 108*53c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0, 109*53c45f0cShuang lin 110*53c45f0cShuang lin /* DDRPHY_REG8 */ 111*53c45f0cShuang lin LEFT_CHN_RX_DQS_DELAY_TAP_MASK = 3, 112*53c45f0cShuang lin LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0, 113*53c45f0cShuang lin 114*53c45f0cShuang lin /* DDRPHY_REG9 */ 115*53c45f0cShuang lin RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4, 116*53c45f0cShuang lin RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4, 117*53c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_ENABLE = 1 << 3, 118*53c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_MASK = 7, 119*53c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0, 120*53c45f0cShuang lin 121*53c45f0cShuang lin /* DDRPHY_REG11 */ 122*53c45f0cShuang lin RIGHT_CHN_RX_DQS_DELAY_TAP_MASK = 3, 123*53c45f0cShuang lin RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0, 124*53c45f0cShuang lin 125*53c45f0cShuang lin /* DDRPHY_REG62 */ 126*53c45f0cShuang lin CAL_DONE_MASK = 3, 127*53c45f0cShuang lin HIGH_8BIT_CAL_DONE = 1 << 1, 128*53c45f0cShuang lin LOW_8BIT_CAL_DONE = 1 << 0, 129*53c45f0cShuang lin }; 130*53c45f0cShuang lin 131*53c45f0cShuang lin /* PTCL */ 132*53c45f0cShuang lin enum { 133*53c45f0cShuang lin /* PCTL_DFISTCFG0 */ 134*53c45f0cShuang lin DFI_INIT_START = 1 << 0, 135*53c45f0cShuang lin DFI_DATA_BYTE_DISABLE_EN = 1 << 2, 136*53c45f0cShuang lin 137*53c45f0cShuang lin /* PCTL_DFISTCFG1 */ 138*53c45f0cShuang lin DFI_DRAM_CLK_SR_EN = 1 << 0, 139*53c45f0cShuang lin DFI_DRAM_CLK_DPD_EN = 1 << 1, 140*53c45f0cShuang lin 141*53c45f0cShuang lin /* PCTL_DFISTCFG2 */ 142*53c45f0cShuang lin DFI_PARITY_INTR_EN = 1 << 0, 143*53c45f0cShuang lin DFI_PARITY_EN = 1 << 1, 144*53c45f0cShuang lin 145*53c45f0cShuang lin /* PCTL_DFILPCFG0 */ 146*53c45f0cShuang lin TLP_RESP_TIME_SHIFT = 16, 147*53c45f0cShuang lin LP_SR_EN = 1 << 8, 148*53c45f0cShuang lin LP_PD_EN = 1 << 0, 149*53c45f0cShuang lin 150*53c45f0cShuang lin /* PCTL_DFIODTCFG */ 151*53c45f0cShuang lin RANK0_ODT_WRITE_SEL = 1 << 3, 152*53c45f0cShuang lin RANK1_ODT_WRITE_SEL = 1 << 11, 153*53c45f0cShuang lin 154*53c45f0cShuang lin /* PCTL_DFIODTCFG1 */ 155*53c45f0cShuang lin ODT_LEN_BL8_W_SHIFT = 16, 156*53c45f0cShuang lin 157*53c45f0cShuang lin /* PCTL_MCFG */ 158*53c45f0cShuang lin TFAW_CFG_MASK = 3, 159*53c45f0cShuang lin TFAW_CFG_SHIFT = 18, 160*53c45f0cShuang lin PD_EXIT_SLOW_MODE = 0 << 17, 161*53c45f0cShuang lin PD_ACTIVE_POWER_DOWN = 1 << 16, 162*53c45f0cShuang lin PD_IDLE_MASK = 0xff, 163*53c45f0cShuang lin PD_IDLE_SHIFT = 8, 164*53c45f0cShuang lin MEM_BL4 = 0 << 0, 165*53c45f0cShuang lin MEM_BL8 = 1 << 0, 166*53c45f0cShuang lin 167*53c45f0cShuang lin /* PCTL_MCFG1 */ 168*53c45f0cShuang lin HW_EXIT_IDLE_EN_MASK = 1, 169*53c45f0cShuang lin HW_EXIT_IDLE_EN_SHIFT = 31, 170*53c45f0cShuang lin SR_IDLE_MASK = 0x1ff, 171*53c45f0cShuang lin SR_IDLE_SHIFT = 0, 172*53c45f0cShuang lin 173*53c45f0cShuang lin /* PCTL_SCFG */ 174*53c45f0cShuang lin HW_LOW_POWER_EN = 1 << 0, 175*53c45f0cShuang lin 176*53c45f0cShuang lin /* PCTL_POWCTL */ 177*53c45f0cShuang lin POWER_UP_START = 1 << 0, 178*53c45f0cShuang lin 179*53c45f0cShuang lin /* PCTL_POWSTAT */ 180*53c45f0cShuang lin POWER_UP_DONE = 1 << 0, 181*53c45f0cShuang lin 182*53c45f0cShuang lin /* PCTL_MCMD */ 183*53c45f0cShuang lin START_CMD = 1 << 31, 184*53c45f0cShuang lin BANK_ADDR_MASK = 7, 185*53c45f0cShuang lin BANK_ADDR_SHIFT = 17, 186*53c45f0cShuang lin CMD_ADDR_MASK = 0x1fff, 187*53c45f0cShuang lin CMD_ADDR_SHIFT = 4, 188*53c45f0cShuang lin DESELECT_CMD = 0, 189*53c45f0cShuang lin PREA_CMD, 190*53c45f0cShuang lin REF_CMD, 191*53c45f0cShuang lin MRS_CMD, 192*53c45f0cShuang lin ZQCS_CMD, 193*53c45f0cShuang lin ZQCL_CMD, 194*53c45f0cShuang lin RSTL_CMD, 195*53c45f0cShuang lin MRR_CMD = 8, 196*53c45f0cShuang lin 197*53c45f0cShuang lin /* PCTL_STAT */ 198*53c45f0cShuang lin INIT_MEM = 0, 199*53c45f0cShuang lin CONFIG, 200*53c45f0cShuang lin CONFIG_REQ, 201*53c45f0cShuang lin ACCESS, 202*53c45f0cShuang lin ACCESS_REQ, 203*53c45f0cShuang lin LOW_POWER, 204*53c45f0cShuang lin LOW_POWER_ENTRY_REQ, 205*53c45f0cShuang lin LOW_POWER_EXIT_REQ, 206*53c45f0cShuang lin PCTL_STAT_MASK = 7, 207*53c45f0cShuang lin 208*53c45f0cShuang lin /* PCTL_SCTL */ 209*53c45f0cShuang lin INIT_STATE = 0, 210*53c45f0cShuang lin CFG_STATE = 1, 211*53c45f0cShuang lin GO_STATE = 2, 212*53c45f0cShuang lin SLEEP_STATE = 3, 213*53c45f0cShuang lin WAKEUP_STATE = 4, 214*53c45f0cShuang lin }; 215*53c45f0cShuang lin 216*53c45f0cShuang lin /* GRF_SOC_CON2 */ 217*53c45f0cShuang lin #define MSCH4_MAINDDR3 (1 << 7) 218*53c45f0cShuang lin #define PHY_DRV_ODT_SET(n) ((n << 4) | n) 219*53c45f0cShuang lin #define DDR3_DLL_RESET (1 << 8) 220*53c45f0cShuang lin 221*53c45f0cShuang lin /* CK pull up/down driver strength control */ 222*53c45f0cShuang lin enum { 223*53c45f0cShuang lin PHY_RON_DISABLE = 0, 224*53c45f0cShuang lin PHY_RON_309OHM = 1, 225*53c45f0cShuang lin PHY_RON_155OHM, 226*53c45f0cShuang lin PHY_RON_103OHM = 3, 227*53c45f0cShuang lin PHY_RON_63OHM = 5, 228*53c45f0cShuang lin PHY_RON_45OHM = 7, 229*53c45f0cShuang lin PHY_RON_77OHM, 230*53c45f0cShuang lin PHY_RON_62OHM, 231*53c45f0cShuang lin PHY_RON_52OHM, 232*53c45f0cShuang lin PHY_RON_44OHM, 233*53c45f0cShuang lin PHY_RON_39OHM, 234*53c45f0cShuang lin PHY_RON_34OHM, 235*53c45f0cShuang lin PHY_RON_31OHM, 236*53c45f0cShuang lin PHY_RON_28OHM, 237*53c45f0cShuang lin }; 238*53c45f0cShuang lin 239*53c45f0cShuang lin /* DQ pull up/down control */ 240*53c45f0cShuang lin enum { 241*53c45f0cShuang lin PHY_RTT_DISABLE = 0, 242*53c45f0cShuang lin PHY_RTT_861OHM = 1, 243*53c45f0cShuang lin PHY_RTT_431OHM, 244*53c45f0cShuang lin PHY_RTT_287OHM, 245*53c45f0cShuang lin PHY_RTT_216OHM, 246*53c45f0cShuang lin PHY_RTT_172OHM, 247*53c45f0cShuang lin PHY_RTT_145OHM, 248*53c45f0cShuang lin PHY_RTT_124OHM, 249*53c45f0cShuang lin PHY_RTT_215OHM, 250*53c45f0cShuang lin PHY_RTT_144OHM = 0xa, 251*53c45f0cShuang lin PHY_RTT_123OHM, 252*53c45f0cShuang lin PHY_RTT_108OHM, 253*53c45f0cShuang lin PHY_RTT_96OHM, 254*53c45f0cShuang lin PHY_RTT_86OHM, 255*53c45f0cShuang lin PHY_RTT_78OHM, 256*53c45f0cShuang lin }; 257*53c45f0cShuang lin 258*53c45f0cShuang lin /* DQS squelch DLL delay */ 259*53c45f0cShuang lin enum { 260*53c45f0cShuang lin DQS_DLL_NO_DELAY = 0, 261*53c45f0cShuang lin DQS_DLL_22P5_DELAY, 262*53c45f0cShuang lin DQS_DLL_45_DELAY, 263*53c45f0cShuang lin DQS_DLL_67P5_DELAY, 264*53c45f0cShuang lin DQS_DLL_90_DELAY, 265*53c45f0cShuang lin DQS_DLL_112P5_DELAY, 266*53c45f0cShuang lin DQS_DLL_135_DELAY, 267*53c45f0cShuang lin DQS_DLL_157P5_DELAY, 268*53c45f0cShuang lin }; 269*53c45f0cShuang lin 270*53c45f0cShuang lin /* GRF_OS_REG1 */ 271*53c45f0cShuang lin enum { 272*53c45f0cShuang lin /* 273*53c45f0cShuang lin * 000: lpddr 274*53c45f0cShuang lin * 001: ddr 275*53c45f0cShuang lin * 010: ddr2 276*53c45f0cShuang lin * 011: ddr3 277*53c45f0cShuang lin * 100: lpddr2-s2 278*53c45f0cShuang lin * 101: lpddr2-s4 279*53c45f0cShuang lin * 110: lpddr3 280*53c45f0cShuang lin */ 281*53c45f0cShuang lin DDR_TYPE_MASK = 7, 282*53c45f0cShuang lin DDR_TYPE_SHIFT = 13, 283*53c45f0cShuang lin 284*53c45f0cShuang lin /* 0: 1 chn, 1: 2 chn */ 285*53c45f0cShuang lin DDR_CHN_CNT_SHIFT = 12, 286*53c45f0cShuang lin 287*53c45f0cShuang lin /* 0: 1 rank, 1: 2 rank */ 288*53c45f0cShuang lin DDR_RANK_CNT_MASK = 1, 289*53c45f0cShuang lin DDR_RANK_CNT_SHIFT = 11, 290*53c45f0cShuang lin 291*53c45f0cShuang lin /* 292*53c45f0cShuang lin * 00: 9col 293*53c45f0cShuang lin * 01: 10col 294*53c45f0cShuang lin * 10: 11col 295*53c45f0cShuang lin * 11: 12col 296*53c45f0cShuang lin */ 297*53c45f0cShuang lin DDR_COL_MASK = 3, 298*53c45f0cShuang lin DDR_COL_SHIFT = 9, 299*53c45f0cShuang lin 300*53c45f0cShuang lin /* 0: 8 bank, 1: 4 bank*/ 301*53c45f0cShuang lin DDR_BANK_MASK = 1, 302*53c45f0cShuang lin DDR_BANK_SHIFT = 8, 303*53c45f0cShuang lin 304*53c45f0cShuang lin /* 305*53c45f0cShuang lin * 00: 13 row 306*53c45f0cShuang lin * 01: 14 row 307*53c45f0cShuang lin * 10: 15 row 308*53c45f0cShuang lin * 11: 16 row 309*53c45f0cShuang lin */ 310*53c45f0cShuang lin DDR_CS0_ROW_MASK = 3, 311*53c45f0cShuang lin DDR_CS0_ROW_SHIFT = 6, 312*53c45f0cShuang lin DDR_CS1_ROW_MASK = 3, 313*53c45f0cShuang lin DDR_CS1_ROW_SHIFT = 4, 314*53c45f0cShuang lin 315*53c45f0cShuang lin /* 316*53c45f0cShuang lin * 00: 32 bit 317*53c45f0cShuang lin * 01: 16 bit 318*53c45f0cShuang lin * 10: 8 bit 319*53c45f0cShuang lin * rk3036 only support 16bit 320*53c45f0cShuang lin */ 321*53c45f0cShuang lin DDR_BW_MASK = 3, 322*53c45f0cShuang lin DDR_BW_SHIFT = 2, 323*53c45f0cShuang lin DDR_DIE_BW_MASK = 3, 324*53c45f0cShuang lin DDR_DIE_BW_SHIFT = 0, 325*53c45f0cShuang lin }; 326*53c45f0cShuang lin 327*53c45f0cShuang lin static void rkdclk_init(struct rk3036_sdram_priv *priv) 328*53c45f0cShuang lin { 329*53c45f0cShuang lin struct rk3036_pll *pll = &priv->cru->pll[1]; 330*53c45f0cShuang lin 331*53c45f0cShuang lin /* pll enter slow-mode */ 332*53c45f0cShuang lin rk_clrsetreg(&priv->cru->cru_mode_con, 333*53c45f0cShuang lin DPLL_MODE_MASK << DPLL_MODE_SHIFT, 334*53c45f0cShuang lin DPLL_MODE_SLOW << DPLL_MODE_SHIFT); 335*53c45f0cShuang lin 336*53c45f0cShuang lin /* use integer mode */ 337*53c45f0cShuang lin rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); 338*53c45f0cShuang lin 339*53c45f0cShuang lin rk_clrsetreg(&pll->con0, 340*53c45f0cShuang lin PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | PLL_FBDIV_MASK, 341*53c45f0cShuang lin (dpll_init_cfg.postdiv1 << PLL_POSTDIV1_SHIFT) | 342*53c45f0cShuang lin dpll_init_cfg.fbdiv); 343*53c45f0cShuang lin rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT | 344*53c45f0cShuang lin PLL_REFDIV_MASK << PLL_REFDIV_SHIFT, 345*53c45f0cShuang lin (dpll_init_cfg.postdiv2 << PLL_POSTDIV2_SHIFT | 346*53c45f0cShuang lin dpll_init_cfg.refdiv << PLL_REFDIV_SHIFT)); 347*53c45f0cShuang lin 348*53c45f0cShuang lin /* waiting for pll lock */ 349*53c45f0cShuang lin while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) 350*53c45f0cShuang lin rockchip_udelay(1); 351*53c45f0cShuang lin 352*53c45f0cShuang lin /* PLL enter normal-mode */ 353*53c45f0cShuang lin rk_clrsetreg(&priv->cru->cru_mode_con, 354*53c45f0cShuang lin DPLL_MODE_MASK << DPLL_MODE_SHIFT, 355*53c45f0cShuang lin DPLL_MODE_NORM << DPLL_MODE_SHIFT); 356*53c45f0cShuang lin } 357*53c45f0cShuang lin 358*53c45f0cShuang lin static void copy_to_reg(u32 *dest, const u32 *src, u32 n) 359*53c45f0cShuang lin { 360*53c45f0cShuang lin int i; 361*53c45f0cShuang lin 362*53c45f0cShuang lin for (i = 0; i < n / sizeof(u32); i++) { 363*53c45f0cShuang lin writel(*src, dest); 364*53c45f0cShuang lin src++; 365*53c45f0cShuang lin dest++; 366*53c45f0cShuang lin } 367*53c45f0cShuang lin } 368*53c45f0cShuang lin 369*53c45f0cShuang lin void phy_pctrl_reset(struct rk3036_sdram_priv *priv) 370*53c45f0cShuang lin { 371*53c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy; 372*53c45f0cShuang lin 373*53c45f0cShuang lin rk_clrsetreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | 374*53c45f0cShuang lin 1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT | 375*53c45f0cShuang lin 1 << DDRPHY_SRST_SHIFT, 376*53c45f0cShuang lin 1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT | 377*53c45f0cShuang lin 1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT); 378*53c45f0cShuang lin 379*53c45f0cShuang lin rockchip_udelay(10); 380*53c45f0cShuang lin 381*53c45f0cShuang lin rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT | 382*53c45f0cShuang lin 1 << DDRPHY_SRST_SHIFT); 383*53c45f0cShuang lin rockchip_udelay(10); 384*53c45f0cShuang lin 385*53c45f0cShuang lin rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | 386*53c45f0cShuang lin 1 << DDRCTRL_SRST_SHIFT); 387*53c45f0cShuang lin rockchip_udelay(10); 388*53c45f0cShuang lin 389*53c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg1, 390*53c45f0cShuang lin SOFT_RESET_MASK << SOFT_RESET_SHIFT, 391*53c45f0cShuang lin 0 << SOFT_RESET_SHIFT); 392*53c45f0cShuang lin rockchip_udelay(10); 393*53c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg1, 394*53c45f0cShuang lin SOFT_RESET_MASK << SOFT_RESET_SHIFT, 395*53c45f0cShuang lin 3 << SOFT_RESET_SHIFT); 396*53c45f0cShuang lin 397*53c45f0cShuang lin rockchip_udelay(1); 398*53c45f0cShuang lin } 399*53c45f0cShuang lin 400*53c45f0cShuang lin void phy_dll_bypass_set(struct rk3036_sdram_priv *priv, unsigned int freq) 401*53c45f0cShuang lin { 402*53c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy; 403*53c45f0cShuang lin 404*53c45f0cShuang lin if (freq < ddr_timing.freq) { 405*53c45f0cShuang lin writel(CMD_DLL_BYPASS | HIGH_8BIT_DLL_BYPASS | 406*53c45f0cShuang lin LOW_8BIT_DLL_BYPASS, &ddr_phy->ddrphy_reg2a); 407*53c45f0cShuang lin 408*53c45f0cShuang lin writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_90 | 409*53c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_ENABLE | 410*53c45f0cShuang lin (0 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) << 411*53c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg6); 412*53c45f0cShuang lin 413*53c45f0cShuang lin writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 | 414*53c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_ENABLE | 415*53c45f0cShuang lin (0 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) << 416*53c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT, 417*53c45f0cShuang lin &ddr_phy->ddrphy_reg9); 418*53c45f0cShuang lin } else { 419*53c45f0cShuang lin writel(CMD_DLL_BYPASS_DISABLE | HIGH_8BIT_DLL_BYPASS_DISABLE | 420*53c45f0cShuang lin LOW_8BIT_DLL_BYPASS_DISABLE, &ddr_phy->ddrphy_reg2a); 421*53c45f0cShuang lin 422*53c45f0cShuang lin writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_0 | 423*53c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_ENABLE | 424*53c45f0cShuang lin (4 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) << 425*53c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT, 426*53c45f0cShuang lin &ddr_phy->ddrphy_reg6); 427*53c45f0cShuang lin 428*53c45f0cShuang lin writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 | 429*53c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_ENABLE | 430*53c45f0cShuang lin (4 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) << 431*53c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT, 432*53c45f0cShuang lin &ddr_phy->ddrphy_reg9); 433*53c45f0cShuang lin } 434*53c45f0cShuang lin 435*53c45f0cShuang lin writel(CMD_SLAVE_DLL_NO_INVERSE_MODE | CMD_SLAVE_DLL_ENALBE | 436*53c45f0cShuang lin (0 & CMD_TX_SLAVE_DLL_DELAY_MASK) << 437*53c45f0cShuang lin CMD_TX_SLAVE_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg19); 438*53c45f0cShuang lin 439*53c45f0cShuang lin /* 45 degree delay */ 440*53c45f0cShuang lin writel((DQS_DLL_45_DELAY & LEFT_CHN_RX_DQS_DELAY_TAP_MASK) << 441*53c45f0cShuang lin LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg8); 442*53c45f0cShuang lin writel((DQS_DLL_45_DELAY & RIGHT_CHN_RX_DQS_DELAY_TAP_MASK) << 443*53c45f0cShuang lin RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg11); 444*53c45f0cShuang lin } 445*53c45f0cShuang lin 446*53c45f0cShuang lin static void send_command(struct rk3036_ddr_pctl *pctl, 447*53c45f0cShuang lin u32 rank, u32 cmd, u32 arg) 448*53c45f0cShuang lin { 449*53c45f0cShuang lin writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd); 450*53c45f0cShuang lin rockchip_udelay(1); 451*53c45f0cShuang lin while (readl(&pctl->mcmd) & START_CMD) 452*53c45f0cShuang lin ; 453*53c45f0cShuang lin } 454*53c45f0cShuang lin 455*53c45f0cShuang lin static void memory_init(struct rk3036_sdram_priv *priv) 456*53c45f0cShuang lin { 457*53c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 458*53c45f0cShuang lin 459*53c45f0cShuang lin send_command(pctl, 3, DESELECT_CMD, 0); 460*53c45f0cShuang lin rockchip_udelay(1); 461*53c45f0cShuang lin send_command(pctl, 3, PREA_CMD, 0); 462*53c45f0cShuang lin send_command(pctl, 3, MRS_CMD, 463*53c45f0cShuang lin (0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | 464*53c45f0cShuang lin (ddr_timing.phy_timing.mr[2] & CMD_ADDR_MASK) << 465*53c45f0cShuang lin CMD_ADDR_SHIFT); 466*53c45f0cShuang lin 467*53c45f0cShuang lin send_command(pctl, 3, MRS_CMD, 468*53c45f0cShuang lin (0x03 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | 469*53c45f0cShuang lin (ddr_timing.phy_timing.mr[3] & CMD_ADDR_MASK) << 470*53c45f0cShuang lin CMD_ADDR_SHIFT); 471*53c45f0cShuang lin 472*53c45f0cShuang lin send_command(pctl, 3, MRS_CMD, 473*53c45f0cShuang lin (0x01 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | 474*53c45f0cShuang lin (ddr_timing.phy_timing.mr[1] & CMD_ADDR_MASK) << 475*53c45f0cShuang lin CMD_ADDR_SHIFT); 476*53c45f0cShuang lin 477*53c45f0cShuang lin send_command(pctl, 3, MRS_CMD, 478*53c45f0cShuang lin (0x00 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | 479*53c45f0cShuang lin (ddr_timing.phy_timing.mr[0] & CMD_ADDR_MASK) << 480*53c45f0cShuang lin CMD_ADDR_SHIFT | DDR3_DLL_RESET); 481*53c45f0cShuang lin 482*53c45f0cShuang lin send_command(pctl, 3, ZQCL_CMD, 0); 483*53c45f0cShuang lin } 484*53c45f0cShuang lin 485*53c45f0cShuang lin static void data_training(struct rk3036_sdram_priv *priv) 486*53c45f0cShuang lin { 487*53c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy; 488*53c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 489*53c45f0cShuang lin u32 value; 490*53c45f0cShuang lin 491*53c45f0cShuang lin /* disable auto refresh */ 492*53c45f0cShuang lin value = readl(&pctl->trefi), 493*53c45f0cShuang lin writel(0, &pctl->trefi); 494*53c45f0cShuang lin 495*53c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03, 496*53c45f0cShuang lin DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_CAL_START); 497*53c45f0cShuang lin 498*53c45f0cShuang lin rockchip_udelay(1); 499*53c45f0cShuang lin while ((readl(&ddr_phy->ddrphy_reg62) & CAL_DONE_MASK) != 500*53c45f0cShuang lin (HIGH_8BIT_CAL_DONE | LOW_8BIT_CAL_DONE)) { 501*53c45f0cShuang lin ; 502*53c45f0cShuang lin } 503*53c45f0cShuang lin 504*53c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03, 505*53c45f0cShuang lin DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_NO_CAL); 506*53c45f0cShuang lin 507*53c45f0cShuang lin /* 508*53c45f0cShuang lin * since data training will take about 20us, so send some auto 509*53c45f0cShuang lin * refresh(about 7.8us) to complement the lost time 510*53c45f0cShuang lin */ 511*53c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0); 512*53c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0); 513*53c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0); 514*53c45f0cShuang lin 515*53c45f0cShuang lin writel(value, &pctl->trefi); 516*53c45f0cShuang lin } 517*53c45f0cShuang lin 518*53c45f0cShuang lin static void move_to_config_state(struct rk3036_sdram_priv *priv) 519*53c45f0cShuang lin { 520*53c45f0cShuang lin unsigned int state; 521*53c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 522*53c45f0cShuang lin 523*53c45f0cShuang lin while (1) { 524*53c45f0cShuang lin state = readl(&pctl->stat) & PCTL_STAT_MASK; 525*53c45f0cShuang lin switch (state) { 526*53c45f0cShuang lin case LOW_POWER: 527*53c45f0cShuang lin writel(WAKEUP_STATE, &pctl->sctl); 528*53c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) 529*53c45f0cShuang lin != ACCESS) 530*53c45f0cShuang lin ; 531*53c45f0cShuang lin /* 532*53c45f0cShuang lin * If at low power state, need wakeup first, and then 533*53c45f0cShuang lin * enter the config, so fallthrough 534*53c45f0cShuang lin */ 535*53c45f0cShuang lin case ACCESS: 536*53c45f0cShuang lin /* fallthrough */ 537*53c45f0cShuang lin case INIT_MEM: 538*53c45f0cShuang lin writel(CFG_STATE, &pctl->sctl); 539*53c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) 540*53c45f0cShuang lin ; 541*53c45f0cShuang lin break; 542*53c45f0cShuang lin case CONFIG: 543*53c45f0cShuang lin return; 544*53c45f0cShuang lin default: 545*53c45f0cShuang lin break; 546*53c45f0cShuang lin } 547*53c45f0cShuang lin } 548*53c45f0cShuang lin } 549*53c45f0cShuang lin 550*53c45f0cShuang lin static void move_to_access_state(struct rk3036_sdram_priv *priv) 551*53c45f0cShuang lin { 552*53c45f0cShuang lin unsigned int state; 553*53c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 554*53c45f0cShuang lin 555*53c45f0cShuang lin while (1) { 556*53c45f0cShuang lin state = readl(&pctl->stat) & PCTL_STAT_MASK; 557*53c45f0cShuang lin switch (state) { 558*53c45f0cShuang lin case LOW_POWER: 559*53c45f0cShuang lin writel(WAKEUP_STATE, &pctl->sctl); 560*53c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) 561*53c45f0cShuang lin ; 562*53c45f0cShuang lin break; 563*53c45f0cShuang lin case INIT_MEM: 564*53c45f0cShuang lin writel(CFG_STATE, &pctl->sctl); 565*53c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) 566*53c45f0cShuang lin ; 567*53c45f0cShuang lin /* fallthrough */ 568*53c45f0cShuang lin case CONFIG: 569*53c45f0cShuang lin writel(GO_STATE, &pctl->sctl); 570*53c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) 571*53c45f0cShuang lin ; 572*53c45f0cShuang lin break; 573*53c45f0cShuang lin case ACCESS: 574*53c45f0cShuang lin return; 575*53c45f0cShuang lin default: 576*53c45f0cShuang lin break; 577*53c45f0cShuang lin } 578*53c45f0cShuang lin } 579*53c45f0cShuang lin } 580*53c45f0cShuang lin 581*53c45f0cShuang lin static void pctl_cfg(struct rk3036_sdram_priv *priv) 582*53c45f0cShuang lin { 583*53c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 584*53c45f0cShuang lin u32 burst_len; 585*53c45f0cShuang lin u32 reg; 586*53c45f0cShuang lin 587*53c45f0cShuang lin writel(DFI_INIT_START | DFI_DATA_BYTE_DISABLE_EN, &pctl->dfistcfg0); 588*53c45f0cShuang lin writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, &pctl->dfistcfg1); 589*53c45f0cShuang lin writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2); 590*53c45f0cShuang lin writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN, 591*53c45f0cShuang lin &pctl->dfilpcfg0); 592*53c45f0cShuang lin 593*53c45f0cShuang lin writel(1, &pctl->dfitphyupdtype0); 594*53c45f0cShuang lin writel(0x0d, &pctl->dfitphyrdlat); 595*53c45f0cShuang lin 596*53c45f0cShuang lin /* cs0 and cs1 write odt enable */ 597*53c45f0cShuang lin writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL), 598*53c45f0cShuang lin &pctl->dfiodtcfg); 599*53c45f0cShuang lin 600*53c45f0cShuang lin /* odt write length */ 601*53c45f0cShuang lin writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1); 602*53c45f0cShuang lin 603*53c45f0cShuang lin /* phyupd and ctrlupd disabled */ 604*53c45f0cShuang lin writel(0, &pctl->dfiupdcfg); 605*53c45f0cShuang lin 606*53c45f0cShuang lin if ((ddr_timing.noc_timing.burstlen << 1) == 4) 607*53c45f0cShuang lin burst_len = MEM_BL4; 608*53c45f0cShuang lin else 609*53c45f0cShuang lin burst_len = MEM_BL8; 610*53c45f0cShuang lin 611*53c45f0cShuang lin copy_to_reg(&pctl->togcnt1u, &ddr_timing.pctl_timing.togcnt1u, 612*53c45f0cShuang lin sizeof(struct rk3036_pctl_timing)); 613*53c45f0cShuang lin reg = readl(&pctl->tcl); 614*53c45f0cShuang lin writel(reg - 3, &pctl->dfitrddataen); 615*53c45f0cShuang lin reg = readl(&pctl->tcwl); 616*53c45f0cShuang lin writel(reg - 1, &pctl->dfitphywrlat); 617*53c45f0cShuang lin 618*53c45f0cShuang lin writel(burst_len | (1 & TFAW_CFG_MASK) << TFAW_CFG_SHIFT | 619*53c45f0cShuang lin PD_EXIT_SLOW_MODE | PD_ACTIVE_POWER_DOWN | 620*53c45f0cShuang lin (0 & PD_IDLE_MASK) << PD_IDLE_SHIFT, 621*53c45f0cShuang lin &pctl->mcfg); 622*53c45f0cShuang lin 623*53c45f0cShuang lin writel(RK_SETBITS(MSCH4_MAINDDR3), &priv->grf->soc_con2); 624*53c45f0cShuang lin setbits_le32(&pctl->scfg, HW_LOW_POWER_EN); 625*53c45f0cShuang lin } 626*53c45f0cShuang lin 627*53c45f0cShuang lin static void phy_cfg(struct rk3036_sdram_priv *priv) 628*53c45f0cShuang lin { 629*53c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy; 630*53c45f0cShuang lin struct rk3036_service_sys *axi_bus = priv->axi_bus; 631*53c45f0cShuang lin 632*53c45f0cShuang lin writel(ddr_timing.noc_timing.noc_timing, &axi_bus->ddrtiming); 633*53c45f0cShuang lin writel(0x3f, &axi_bus->readlatency); 634*53c45f0cShuang lin 635*53c45f0cShuang lin writel(MEMORY_SELECT_DDR3 | DQS_SQU_CAL_NORMAL_MODE, 636*53c45f0cShuang lin &ddr_phy->ddrphy_reg2); 637*53c45f0cShuang lin 638*53c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg3, 1, ddr_timing.phy_timing.bl); 639*53c45f0cShuang lin writel(ddr_timing.phy_timing.cl_al, &ddr_phy->ddrphy_reg4a); 640*53c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg16); 641*53c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg22); 642*53c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg25); 643*53c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg26); 644*53c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg27); 645*53c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg28); 646*53c45f0cShuang lin } 647*53c45f0cShuang lin 648*53c45f0cShuang lin void dram_cfg_rbc(struct rk3036_sdram_priv *priv) 649*53c45f0cShuang lin { 650*53c45f0cShuang lin char noc_config; 651*53c45f0cShuang lin int i = 0; 652*53c45f0cShuang lin struct rk3036_ddr_config config = priv->ddr_config; 653*53c45f0cShuang lin struct rk3036_service_sys *axi_bus = priv->axi_bus; 654*53c45f0cShuang lin 655*53c45f0cShuang lin move_to_config_state(priv); 656*53c45f0cShuang lin 657*53c45f0cShuang lin /* 2bit in BIT1, 2 */ 658*53c45f0cShuang lin if (config.rank == 2) { 659*53c45f0cShuang lin noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 | 660*53c45f0cShuang lin 1 << 3 | (config.col - 10); 661*53c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[9]) { 662*53c45f0cShuang lin i = 9; 663*53c45f0cShuang lin goto finish; 664*53c45f0cShuang lin } else if (noc_config == ddr_cfg_2_rbc[10]) { 665*53c45f0cShuang lin i = 10; 666*53c45f0cShuang lin goto finish; 667*53c45f0cShuang lin } 668*53c45f0cShuang lin } 669*53c45f0cShuang lin 670*53c45f0cShuang lin noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 | 671*53c45f0cShuang lin (config.col - 10); 672*53c45f0cShuang lin 673*53c45f0cShuang lin for (i = 0; i < sizeof(ddr_cfg_2_rbc); i++) { 674*53c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[i]) 675*53c45f0cShuang lin goto finish; 676*53c45f0cShuang lin } 677*53c45f0cShuang lin 678*53c45f0cShuang lin /* bank: 1 bit in BIT6,7, 1bit in BIT1, 2 */ 679*53c45f0cShuang lin noc_config = 1 << 6 | (config.cs0_row - 13) << 4 | 680*53c45f0cShuang lin 2 << 1 | (config.col - 10); 681*53c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[11]) { 682*53c45f0cShuang lin i = 11; 683*53c45f0cShuang lin goto finish; 684*53c45f0cShuang lin } 685*53c45f0cShuang lin 686*53c45f0cShuang lin /* bank: 2bit in BIT6,7 */ 687*53c45f0cShuang lin noc_config = (config.bank << 6) | (config.cs0_row - 13) << 4 | 688*53c45f0cShuang lin (config.col - 10); 689*53c45f0cShuang lin 690*53c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[0]) 691*53c45f0cShuang lin i = 0; 692*53c45f0cShuang lin else if (noc_config == ddr_cfg_2_rbc[12]) 693*53c45f0cShuang lin i = 12; 694*53c45f0cShuang lin else if (noc_config == ddr_cfg_2_rbc[13]) 695*53c45f0cShuang lin i = 13; 696*53c45f0cShuang lin finish: 697*53c45f0cShuang lin writel(i, &axi_bus->ddrconf); 698*53c45f0cShuang lin move_to_access_state(priv); 699*53c45f0cShuang lin } 700*53c45f0cShuang lin 701*53c45f0cShuang lin static void sdram_all_config(struct rk3036_sdram_priv *priv) 702*53c45f0cShuang lin { 703*53c45f0cShuang lin u32 os_reg = 0; 704*53c45f0cShuang lin struct rk3036_ddr_config config = priv->ddr_config; 705*53c45f0cShuang lin 706*53c45f0cShuang lin os_reg = config.ddr_type << DDR_TYPE_SHIFT | 707*53c45f0cShuang lin 0 << DDR_CHN_CNT_SHIFT | 708*53c45f0cShuang lin (config.rank - 1) << DDR_RANK_CNT_SHIFT | 709*53c45f0cShuang lin (config.col - 1) << DDR_COL_SHIFT | 710*53c45f0cShuang lin (config.bank == 3 ? 0 : 1) << DDR_BANK_SHIFT | 711*53c45f0cShuang lin (config.cs0_row - 13) << DDR_CS0_ROW_SHIFT | 712*53c45f0cShuang lin (config.cs1_row - 13) << DDR_CS1_ROW_SHIFT | 713*53c45f0cShuang lin 1 << DDR_BW_SHIFT | config.bw << DDR_DIE_BW_SHIFT; 714*53c45f0cShuang lin writel(os_reg, &priv->grf->os_reg[1]); 715*53c45f0cShuang lin } 716*53c45f0cShuang lin 717*53c45f0cShuang lin size_t sdram_size(void) 718*53c45f0cShuang lin { 719*53c45f0cShuang lin u32 size, os_reg, cs0_row, cs1_row, col, bank, rank; 720*53c45f0cShuang lin struct rk3036_grf *grf = (void *)GRF_BASE; 721*53c45f0cShuang lin 722*53c45f0cShuang lin os_reg = readl(&grf->os_reg[1]); 723*53c45f0cShuang lin 724*53c45f0cShuang lin cs0_row = 13 + ((os_reg >> DDR_CS0_ROW_SHIFT) & DDR_CS0_ROW_MASK); 725*53c45f0cShuang lin cs1_row = 13 + ((os_reg >> DDR_CS1_ROW_SHIFT) & DDR_CS1_ROW_MASK); 726*53c45f0cShuang lin col = 9 + ((os_reg >> DDR_COL_SHIFT) & DDR_COL_MASK); 727*53c45f0cShuang lin bank = 3 - ((os_reg >> DDR_BANK_SHIFT) & DDR_BANK_MASK); 728*53c45f0cShuang lin rank = 1 + ((os_reg >> DDR_RANK_CNT_SHIFT) & DDR_RANK_CNT_MASK); 729*53c45f0cShuang lin 730*53c45f0cShuang lin /* row + col + bank + bw(rk3036 only support 16bit, so fix in 1) */ 731*53c45f0cShuang lin size = 1 << (cs0_row + col + bank + 1); 732*53c45f0cShuang lin 733*53c45f0cShuang lin if (rank > 1) 734*53c45f0cShuang lin size += size >> (cs0_row - cs1_row); 735*53c45f0cShuang lin 736*53c45f0cShuang lin return size; 737*53c45f0cShuang lin } 738*53c45f0cShuang lin 739*53c45f0cShuang lin void sdram_init(void) 740*53c45f0cShuang lin { 741*53c45f0cShuang lin struct rk3036_sdram_priv sdram_priv; 742*53c45f0cShuang lin 743*53c45f0cShuang lin sdram_priv.cru = (void *)CRU_BASE; 744*53c45f0cShuang lin sdram_priv.grf = (void *)GRF_BASE; 745*53c45f0cShuang lin sdram_priv.phy = (void *)DDR_PHY_BASE; 746*53c45f0cShuang lin sdram_priv.pctl = (void *)DDR_PCTL_BASE; 747*53c45f0cShuang lin sdram_priv.axi_bus = (void *)CPU_AXI_BUS_BASE; 748*53c45f0cShuang lin 749*53c45f0cShuang lin get_ddr_config(&sdram_priv.ddr_config); 750*53c45f0cShuang lin sdram_all_config(&sdram_priv); 751*53c45f0cShuang lin rkdclk_init(&sdram_priv); 752*53c45f0cShuang lin phy_pctrl_reset(&sdram_priv); 753*53c45f0cShuang lin phy_dll_bypass_set(&sdram_priv, ddr_timing.freq); 754*53c45f0cShuang lin pctl_cfg(&sdram_priv); 755*53c45f0cShuang lin phy_cfg(&sdram_priv); 756*53c45f0cShuang lin writel(POWER_UP_START, &sdram_priv.pctl->powctl); 757*53c45f0cShuang lin while (!(readl(&sdram_priv.pctl->powstat) & POWER_UP_DONE)) 758*53c45f0cShuang lin ; 759*53c45f0cShuang lin memory_init(&sdram_priv); 760*53c45f0cShuang lin move_to_config_state(&sdram_priv); 761*53c45f0cShuang lin data_training(&sdram_priv); 762*53c45f0cShuang lin move_to_access_state(&sdram_priv); 763*53c45f0cShuang lin dram_cfg_rbc(&sdram_priv); 764*53c45f0cShuang lin } 765