153c45f0cShuang lin /* 253c45f0cShuang lin * (C) Copyright 2015 Google, Inc 353c45f0cShuang lin * 453c45f0cShuang lin * SPDX-License-Identifier: GPL-2.0+ 553c45f0cShuang lin */ 653c45f0cShuang lin #include <common.h> 753c45f0cShuang lin #include <asm/io.h> 853c45f0cShuang lin #include <asm/types.h> 953c45f0cShuang lin #include <asm/arch/cru_rk3036.h> 1053c45f0cShuang lin #include <asm/arch/grf_rk3036.h> 1153c45f0cShuang lin #include <asm/arch/hardware.h> 1253c45f0cShuang lin #include <asm/arch/sdram_rk3036.h> 1353c45f0cShuang lin #include <asm/arch/timer.h> 1453c45f0cShuang lin #include <asm/arch/uart.h> 1553c45f0cShuang lin 1653c45f0cShuang lin /* 1753c45f0cShuang lin * we can not fit the code to access the device tree in SPL 1853c45f0cShuang lin * (due to 4K SRAM size limits), so these are hard-coded 1953c45f0cShuang lin */ 2053c45f0cShuang lin #define CRU_BASE 0x20000000 2153c45f0cShuang lin #define GRF_BASE 0x20008000 2253c45f0cShuang lin #define DDR_PHY_BASE 0x2000a000 2353c45f0cShuang lin #define DDR_PCTL_BASE 0x20004000 2453c45f0cShuang lin #define CPU_AXI_BUS_BASE 0x10128000 2553c45f0cShuang lin 2653c45f0cShuang lin struct rk3036_sdram_priv { 2753c45f0cShuang lin struct rk3036_cru *cru; 2853c45f0cShuang lin struct rk3036_grf *grf; 2953c45f0cShuang lin struct rk3036_ddr_phy *phy; 3053c45f0cShuang lin struct rk3036_ddr_pctl *pctl; 3153c45f0cShuang lin struct rk3036_service_sys *axi_bus; 3253c45f0cShuang lin 3353c45f0cShuang lin /* ddr die config */ 3453c45f0cShuang lin struct rk3036_ddr_config ddr_config; 3553c45f0cShuang lin }; 3653c45f0cShuang lin 37*faa75ad9SKever Yang /* 38*faa75ad9SKever Yang * use integer mode, dpll output 792MHz and ddr get 396MHz 3953c45f0cShuang lin * refdiv, fbdiv, postdiv1, postdiv2 4053c45f0cShuang lin */ 41*faa75ad9SKever Yang const struct pll_div dpll_init_cfg = {1, 66, 2, 1}; 4253c45f0cShuang lin 4353c45f0cShuang lin /* 396Mhz ddr timing */ 4453c45f0cShuang lin const struct rk3036_ddr_timing ddr_timing = {0x18c, 4553c45f0cShuang lin {0x18c, 0xc8, 0x1f4, 0x27, 0x4e, 4653c45f0cShuang lin 0x4, 0x8b, 0x06, 0x03, 0x0, 0x06, 0x05, 0x0f, 0x15, 0x06, 0x04, 0x04, 4753c45f0cShuang lin 0x06, 0x04, 0x200, 0x03, 0x0a, 0x40, 0x2710, 0x01, 0x05, 0x05, 0x03, 4853c45f0cShuang lin 0x0c, 0x28, 0x100, 0x0, 0x04, 0x0}, 4953c45f0cShuang lin {{0x420, 0x42, 0x0, 0x0}, 0x01, 0x60}, 5053c45f0cShuang lin {0x24717315} }; 5153c45f0cShuang lin 5253c45f0cShuang lin /* 5353c45f0cShuang lin * [7:6] bank(n:n bit bank) 5453c45f0cShuang lin * [5:4] row(13+n) 5553c45f0cShuang lin * [3] cs(0:1 cs, 1:2 cs) 5653c45f0cShuang lin * [2:1] bank(n:n bit bank) 5753c45f0cShuang lin * [0] col(10+n) 5853c45f0cShuang lin */ 5953c45f0cShuang lin const char ddr_cfg_2_rbc[] = { 6053c45f0cShuang lin ((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 1), 6153c45f0cShuang lin ((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 0), 6253c45f0cShuang lin ((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 0), 6353c45f0cShuang lin ((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 0), 6453c45f0cShuang lin ((0 << 6) | (1 << 4) | (0 << 3) | (3 << 1) | 1), 6553c45f0cShuang lin ((0 << 6) | (2 << 4) | (0 << 3) | (3 << 1) | 1), 6653c45f0cShuang lin ((0 << 6) | (3 << 4) | (0 << 3) | (3 << 1) | 1), 6753c45f0cShuang lin ((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 0), 6853c45f0cShuang lin ((0 << 6) | (0 << 4) | (0 << 3) | (3 << 1) | 1), 6953c45f0cShuang lin ((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 0), 7053c45f0cShuang lin ((0 << 6) | (3 << 4) | (1 << 3) | (3 << 1) | 1), 7153c45f0cShuang lin ((1 << 6) | (2 << 4) | (0 << 3) | (2 << 1) | 0), 7253c45f0cShuang lin ((3 << 6) | (2 << 4) | (0 << 3) | (0 << 1) | 1), 7353c45f0cShuang lin ((3 << 6) | (3 << 4) | (0 << 3) | (0 << 1) | 0), 7453c45f0cShuang lin }; 7553c45f0cShuang lin 7653c45f0cShuang lin /* DDRPHY REG */ 7753c45f0cShuang lin enum { 7853c45f0cShuang lin /* DDRPHY_REG1 */ 7953c45f0cShuang lin SOFT_RESET_MASK = 3, 8053c45f0cShuang lin SOFT_RESET_SHIFT = 2, 8153c45f0cShuang lin 8253c45f0cShuang lin /* DDRPHY_REG2 */ 8353c45f0cShuang lin MEMORY_SELECT_DDR3 = 0 << 6, 8453c45f0cShuang lin DQS_SQU_CAL_NORMAL_MODE = 0 << 1, 8553c45f0cShuang lin DQS_SQU_CAL_START = 1 << 0, 8653c45f0cShuang lin DQS_SQU_NO_CAL = 0 << 0, 8753c45f0cShuang lin 8853c45f0cShuang lin /* DDRPHY_REG2A */ 8953c45f0cShuang lin CMD_DLL_BYPASS = 1 << 4, 9053c45f0cShuang lin CMD_DLL_BYPASS_DISABLE = 0 << 4, 9153c45f0cShuang lin HIGH_8BIT_DLL_BYPASS = 1 << 3, 9253c45f0cShuang lin HIGH_8BIT_DLL_BYPASS_DISABLE = 0 << 3, 9353c45f0cShuang lin LOW_8BIT_DLL_BYPASS = 1 << 2, 9453c45f0cShuang lin LOW_8BIT_DLL_BYPASS_DISABLE = 0 << 2, 9553c45f0cShuang lin 9653c45f0cShuang lin /* DDRPHY_REG19 */ 9753c45f0cShuang lin CMD_FEEDBACK_ENABLE = 1 << 5, 9853c45f0cShuang lin CMD_SLAVE_DLL_INVERSE_MODE = 1 << 4, 9953c45f0cShuang lin CMD_SLAVE_DLL_NO_INVERSE_MODE = 0 << 4, 10053c45f0cShuang lin CMD_SLAVE_DLL_ENALBE = 1 << 3, 10153c45f0cShuang lin CMD_TX_SLAVE_DLL_DELAY_MASK = 7, 10253c45f0cShuang lin CMD_TX_SLAVE_DLL_DELAY_SHIFT = 0, 10353c45f0cShuang lin 10453c45f0cShuang lin /* DDRPHY_REG6 */ 10553c45f0cShuang lin LEFT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4, 10653c45f0cShuang lin LEFT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4, 10753c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_ENABLE = 1 << 3, 10853c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_MASK = 7, 10953c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0, 11053c45f0cShuang lin 11153c45f0cShuang lin /* DDRPHY_REG8 */ 11253c45f0cShuang lin LEFT_CHN_RX_DQS_DELAY_TAP_MASK = 3, 11353c45f0cShuang lin LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0, 11453c45f0cShuang lin 11553c45f0cShuang lin /* DDRPHY_REG9 */ 11653c45f0cShuang lin RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 = 1 << 4, 11753c45f0cShuang lin RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 = 0 << 4, 11853c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_ENABLE = 1 << 3, 11953c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_MASK = 7, 12053c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT = 0, 12153c45f0cShuang lin 12253c45f0cShuang lin /* DDRPHY_REG11 */ 12353c45f0cShuang lin RIGHT_CHN_RX_DQS_DELAY_TAP_MASK = 3, 12453c45f0cShuang lin RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT = 0, 12553c45f0cShuang lin 12653c45f0cShuang lin /* DDRPHY_REG62 */ 12753c45f0cShuang lin CAL_DONE_MASK = 3, 12853c45f0cShuang lin HIGH_8BIT_CAL_DONE = 1 << 1, 12953c45f0cShuang lin LOW_8BIT_CAL_DONE = 1 << 0, 13053c45f0cShuang lin }; 13153c45f0cShuang lin 13253c45f0cShuang lin /* PTCL */ 13353c45f0cShuang lin enum { 13453c45f0cShuang lin /* PCTL_DFISTCFG0 */ 13553c45f0cShuang lin DFI_INIT_START = 1 << 0, 13653c45f0cShuang lin DFI_DATA_BYTE_DISABLE_EN = 1 << 2, 13753c45f0cShuang lin 13853c45f0cShuang lin /* PCTL_DFISTCFG1 */ 13953c45f0cShuang lin DFI_DRAM_CLK_SR_EN = 1 << 0, 14053c45f0cShuang lin DFI_DRAM_CLK_DPD_EN = 1 << 1, 14153c45f0cShuang lin 14253c45f0cShuang lin /* PCTL_DFISTCFG2 */ 14353c45f0cShuang lin DFI_PARITY_INTR_EN = 1 << 0, 14453c45f0cShuang lin DFI_PARITY_EN = 1 << 1, 14553c45f0cShuang lin 14653c45f0cShuang lin /* PCTL_DFILPCFG0 */ 14753c45f0cShuang lin TLP_RESP_TIME_SHIFT = 16, 14853c45f0cShuang lin LP_SR_EN = 1 << 8, 14953c45f0cShuang lin LP_PD_EN = 1 << 0, 15053c45f0cShuang lin 15153c45f0cShuang lin /* PCTL_DFIODTCFG */ 15253c45f0cShuang lin RANK0_ODT_WRITE_SEL = 1 << 3, 15353c45f0cShuang lin RANK1_ODT_WRITE_SEL = 1 << 11, 15453c45f0cShuang lin 15553c45f0cShuang lin /* PCTL_DFIODTCFG1 */ 15653c45f0cShuang lin ODT_LEN_BL8_W_SHIFT = 16, 15753c45f0cShuang lin 15853c45f0cShuang lin /* PCTL_MCFG */ 15953c45f0cShuang lin TFAW_CFG_MASK = 3, 16053c45f0cShuang lin TFAW_CFG_SHIFT = 18, 16153c45f0cShuang lin PD_EXIT_SLOW_MODE = 0 << 17, 16253c45f0cShuang lin PD_ACTIVE_POWER_DOWN = 1 << 16, 16353c45f0cShuang lin PD_IDLE_MASK = 0xff, 16453c45f0cShuang lin PD_IDLE_SHIFT = 8, 16553c45f0cShuang lin MEM_BL4 = 0 << 0, 16653c45f0cShuang lin MEM_BL8 = 1 << 0, 16753c45f0cShuang lin 16853c45f0cShuang lin /* PCTL_MCFG1 */ 16953c45f0cShuang lin HW_EXIT_IDLE_EN_MASK = 1, 17053c45f0cShuang lin HW_EXIT_IDLE_EN_SHIFT = 31, 17153c45f0cShuang lin SR_IDLE_MASK = 0x1ff, 17253c45f0cShuang lin SR_IDLE_SHIFT = 0, 17353c45f0cShuang lin 17453c45f0cShuang lin /* PCTL_SCFG */ 17553c45f0cShuang lin HW_LOW_POWER_EN = 1 << 0, 17653c45f0cShuang lin 17753c45f0cShuang lin /* PCTL_POWCTL */ 17853c45f0cShuang lin POWER_UP_START = 1 << 0, 17953c45f0cShuang lin 18053c45f0cShuang lin /* PCTL_POWSTAT */ 18153c45f0cShuang lin POWER_UP_DONE = 1 << 0, 18253c45f0cShuang lin 18353c45f0cShuang lin /* PCTL_MCMD */ 18453c45f0cShuang lin START_CMD = 1 << 31, 18553c45f0cShuang lin BANK_ADDR_MASK = 7, 18653c45f0cShuang lin BANK_ADDR_SHIFT = 17, 18753c45f0cShuang lin CMD_ADDR_MASK = 0x1fff, 18853c45f0cShuang lin CMD_ADDR_SHIFT = 4, 18953c45f0cShuang lin DESELECT_CMD = 0, 19053c45f0cShuang lin PREA_CMD, 19153c45f0cShuang lin REF_CMD, 19253c45f0cShuang lin MRS_CMD, 19353c45f0cShuang lin ZQCS_CMD, 19453c45f0cShuang lin ZQCL_CMD, 19553c45f0cShuang lin RSTL_CMD, 19653c45f0cShuang lin MRR_CMD = 8, 19753c45f0cShuang lin 19853c45f0cShuang lin /* PCTL_STAT */ 19953c45f0cShuang lin INIT_MEM = 0, 20053c45f0cShuang lin CONFIG, 20153c45f0cShuang lin CONFIG_REQ, 20253c45f0cShuang lin ACCESS, 20353c45f0cShuang lin ACCESS_REQ, 20453c45f0cShuang lin LOW_POWER, 20553c45f0cShuang lin LOW_POWER_ENTRY_REQ, 20653c45f0cShuang lin LOW_POWER_EXIT_REQ, 20753c45f0cShuang lin PCTL_STAT_MASK = 7, 20853c45f0cShuang lin 20953c45f0cShuang lin /* PCTL_SCTL */ 21053c45f0cShuang lin INIT_STATE = 0, 21153c45f0cShuang lin CFG_STATE = 1, 21253c45f0cShuang lin GO_STATE = 2, 21353c45f0cShuang lin SLEEP_STATE = 3, 21453c45f0cShuang lin WAKEUP_STATE = 4, 21553c45f0cShuang lin }; 21653c45f0cShuang lin 21753c45f0cShuang lin /* GRF_SOC_CON2 */ 21853c45f0cShuang lin #define MSCH4_MAINDDR3 (1 << 7) 21953c45f0cShuang lin #define PHY_DRV_ODT_SET(n) ((n << 4) | n) 22053c45f0cShuang lin #define DDR3_DLL_RESET (1 << 8) 22153c45f0cShuang lin 22253c45f0cShuang lin /* CK pull up/down driver strength control */ 22353c45f0cShuang lin enum { 22453c45f0cShuang lin PHY_RON_DISABLE = 0, 22553c45f0cShuang lin PHY_RON_309OHM = 1, 22653c45f0cShuang lin PHY_RON_155OHM, 22753c45f0cShuang lin PHY_RON_103OHM = 3, 22853c45f0cShuang lin PHY_RON_63OHM = 5, 22953c45f0cShuang lin PHY_RON_45OHM = 7, 23053c45f0cShuang lin PHY_RON_77OHM, 23153c45f0cShuang lin PHY_RON_62OHM, 23253c45f0cShuang lin PHY_RON_52OHM, 23353c45f0cShuang lin PHY_RON_44OHM, 23453c45f0cShuang lin PHY_RON_39OHM, 23553c45f0cShuang lin PHY_RON_34OHM, 23653c45f0cShuang lin PHY_RON_31OHM, 23753c45f0cShuang lin PHY_RON_28OHM, 23853c45f0cShuang lin }; 23953c45f0cShuang lin 24053c45f0cShuang lin /* DQ pull up/down control */ 24153c45f0cShuang lin enum { 24253c45f0cShuang lin PHY_RTT_DISABLE = 0, 24353c45f0cShuang lin PHY_RTT_861OHM = 1, 24453c45f0cShuang lin PHY_RTT_431OHM, 24553c45f0cShuang lin PHY_RTT_287OHM, 24653c45f0cShuang lin PHY_RTT_216OHM, 24753c45f0cShuang lin PHY_RTT_172OHM, 24853c45f0cShuang lin PHY_RTT_145OHM, 24953c45f0cShuang lin PHY_RTT_124OHM, 25053c45f0cShuang lin PHY_RTT_215OHM, 25153c45f0cShuang lin PHY_RTT_144OHM = 0xa, 25253c45f0cShuang lin PHY_RTT_123OHM, 25353c45f0cShuang lin PHY_RTT_108OHM, 25453c45f0cShuang lin PHY_RTT_96OHM, 25553c45f0cShuang lin PHY_RTT_86OHM, 25653c45f0cShuang lin PHY_RTT_78OHM, 25753c45f0cShuang lin }; 25853c45f0cShuang lin 25953c45f0cShuang lin /* DQS squelch DLL delay */ 26053c45f0cShuang lin enum { 26153c45f0cShuang lin DQS_DLL_NO_DELAY = 0, 26253c45f0cShuang lin DQS_DLL_22P5_DELAY, 26353c45f0cShuang lin DQS_DLL_45_DELAY, 26453c45f0cShuang lin DQS_DLL_67P5_DELAY, 26553c45f0cShuang lin DQS_DLL_90_DELAY, 26653c45f0cShuang lin DQS_DLL_112P5_DELAY, 26753c45f0cShuang lin DQS_DLL_135_DELAY, 26853c45f0cShuang lin DQS_DLL_157P5_DELAY, 26953c45f0cShuang lin }; 27053c45f0cShuang lin 27153c45f0cShuang lin /* GRF_OS_REG1 */ 27253c45f0cShuang lin enum { 27353c45f0cShuang lin /* 27453c45f0cShuang lin * 000: lpddr 27553c45f0cShuang lin * 001: ddr 27653c45f0cShuang lin * 010: ddr2 27753c45f0cShuang lin * 011: ddr3 27853c45f0cShuang lin * 100: lpddr2-s2 27953c45f0cShuang lin * 101: lpddr2-s4 28053c45f0cShuang lin * 110: lpddr3 28153c45f0cShuang lin */ 28253c45f0cShuang lin DDR_TYPE_MASK = 7, 28353c45f0cShuang lin DDR_TYPE_SHIFT = 13, 28453c45f0cShuang lin 28553c45f0cShuang lin /* 0: 1 chn, 1: 2 chn */ 28653c45f0cShuang lin DDR_CHN_CNT_SHIFT = 12, 28753c45f0cShuang lin 28853c45f0cShuang lin /* 0: 1 rank, 1: 2 rank */ 28953c45f0cShuang lin DDR_RANK_CNT_MASK = 1, 29053c45f0cShuang lin DDR_RANK_CNT_SHIFT = 11, 29153c45f0cShuang lin 29253c45f0cShuang lin /* 29353c45f0cShuang lin * 00: 9col 29453c45f0cShuang lin * 01: 10col 29553c45f0cShuang lin * 10: 11col 29653c45f0cShuang lin * 11: 12col 29753c45f0cShuang lin */ 29853c45f0cShuang lin DDR_COL_MASK = 3, 29953c45f0cShuang lin DDR_COL_SHIFT = 9, 30053c45f0cShuang lin 30153c45f0cShuang lin /* 0: 8 bank, 1: 4 bank*/ 30253c45f0cShuang lin DDR_BANK_MASK = 1, 30353c45f0cShuang lin DDR_BANK_SHIFT = 8, 30453c45f0cShuang lin 30553c45f0cShuang lin /* 30653c45f0cShuang lin * 00: 13 row 30753c45f0cShuang lin * 01: 14 row 30853c45f0cShuang lin * 10: 15 row 30953c45f0cShuang lin * 11: 16 row 31053c45f0cShuang lin */ 31153c45f0cShuang lin DDR_CS0_ROW_MASK = 3, 31253c45f0cShuang lin DDR_CS0_ROW_SHIFT = 6, 31353c45f0cShuang lin DDR_CS1_ROW_MASK = 3, 31453c45f0cShuang lin DDR_CS1_ROW_SHIFT = 4, 31553c45f0cShuang lin 31653c45f0cShuang lin /* 31753c45f0cShuang lin * 00: 32 bit 31853c45f0cShuang lin * 01: 16 bit 31953c45f0cShuang lin * 10: 8 bit 32053c45f0cShuang lin * rk3036 only support 16bit 32153c45f0cShuang lin */ 32253c45f0cShuang lin DDR_BW_MASK = 3, 32353c45f0cShuang lin DDR_BW_SHIFT = 2, 32453c45f0cShuang lin DDR_DIE_BW_MASK = 3, 32553c45f0cShuang lin DDR_DIE_BW_SHIFT = 0, 32653c45f0cShuang lin }; 32753c45f0cShuang lin 32853c45f0cShuang lin static void rkdclk_init(struct rk3036_sdram_priv *priv) 32953c45f0cShuang lin { 33053c45f0cShuang lin struct rk3036_pll *pll = &priv->cru->pll[1]; 33153c45f0cShuang lin 33253c45f0cShuang lin /* pll enter slow-mode */ 33353c45f0cShuang lin rk_clrsetreg(&priv->cru->cru_mode_con, 33453c45f0cShuang lin DPLL_MODE_MASK << DPLL_MODE_SHIFT, 33553c45f0cShuang lin DPLL_MODE_SLOW << DPLL_MODE_SHIFT); 33653c45f0cShuang lin 33753c45f0cShuang lin /* use integer mode */ 33853c45f0cShuang lin rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT); 33953c45f0cShuang lin 34053c45f0cShuang lin rk_clrsetreg(&pll->con0, 34153c45f0cShuang lin PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | PLL_FBDIV_MASK, 34253c45f0cShuang lin (dpll_init_cfg.postdiv1 << PLL_POSTDIV1_SHIFT) | 34353c45f0cShuang lin dpll_init_cfg.fbdiv); 34453c45f0cShuang lin rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT | 34553c45f0cShuang lin PLL_REFDIV_MASK << PLL_REFDIV_SHIFT, 34653c45f0cShuang lin (dpll_init_cfg.postdiv2 << PLL_POSTDIV2_SHIFT | 34753c45f0cShuang lin dpll_init_cfg.refdiv << PLL_REFDIV_SHIFT)); 34853c45f0cShuang lin 34953c45f0cShuang lin /* waiting for pll lock */ 35053c45f0cShuang lin while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)) 35153c45f0cShuang lin rockchip_udelay(1); 35253c45f0cShuang lin 35353c45f0cShuang lin /* PLL enter normal-mode */ 35453c45f0cShuang lin rk_clrsetreg(&priv->cru->cru_mode_con, 35553c45f0cShuang lin DPLL_MODE_MASK << DPLL_MODE_SHIFT, 35653c45f0cShuang lin DPLL_MODE_NORM << DPLL_MODE_SHIFT); 35753c45f0cShuang lin } 35853c45f0cShuang lin 35953c45f0cShuang lin static void copy_to_reg(u32 *dest, const u32 *src, u32 n) 36053c45f0cShuang lin { 36153c45f0cShuang lin int i; 36253c45f0cShuang lin 36353c45f0cShuang lin for (i = 0; i < n / sizeof(u32); i++) { 36453c45f0cShuang lin writel(*src, dest); 36553c45f0cShuang lin src++; 36653c45f0cShuang lin dest++; 36753c45f0cShuang lin } 36853c45f0cShuang lin } 36953c45f0cShuang lin 37053c45f0cShuang lin void phy_pctrl_reset(struct rk3036_sdram_priv *priv) 37153c45f0cShuang lin { 37253c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy; 37353c45f0cShuang lin 37453c45f0cShuang lin rk_clrsetreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | 37553c45f0cShuang lin 1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT | 37653c45f0cShuang lin 1 << DDRPHY_SRST_SHIFT, 37753c45f0cShuang lin 1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT | 37853c45f0cShuang lin 1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT); 37953c45f0cShuang lin 38053c45f0cShuang lin rockchip_udelay(10); 38153c45f0cShuang lin 38253c45f0cShuang lin rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT | 38353c45f0cShuang lin 1 << DDRPHY_SRST_SHIFT); 38453c45f0cShuang lin rockchip_udelay(10); 38553c45f0cShuang lin 38653c45f0cShuang lin rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT | 38753c45f0cShuang lin 1 << DDRCTRL_SRST_SHIFT); 38853c45f0cShuang lin rockchip_udelay(10); 38953c45f0cShuang lin 39053c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg1, 39153c45f0cShuang lin SOFT_RESET_MASK << SOFT_RESET_SHIFT, 39253c45f0cShuang lin 0 << SOFT_RESET_SHIFT); 39353c45f0cShuang lin rockchip_udelay(10); 39453c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg1, 39553c45f0cShuang lin SOFT_RESET_MASK << SOFT_RESET_SHIFT, 39653c45f0cShuang lin 3 << SOFT_RESET_SHIFT); 39753c45f0cShuang lin 39853c45f0cShuang lin rockchip_udelay(1); 39953c45f0cShuang lin } 40053c45f0cShuang lin 40153c45f0cShuang lin void phy_dll_bypass_set(struct rk3036_sdram_priv *priv, unsigned int freq) 40253c45f0cShuang lin { 40353c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy; 40453c45f0cShuang lin 40553c45f0cShuang lin if (freq < ddr_timing.freq) { 40653c45f0cShuang lin writel(CMD_DLL_BYPASS | HIGH_8BIT_DLL_BYPASS | 40753c45f0cShuang lin LOW_8BIT_DLL_BYPASS, &ddr_phy->ddrphy_reg2a); 40853c45f0cShuang lin 40953c45f0cShuang lin writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_90 | 41053c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_ENABLE | 41153c45f0cShuang lin (0 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) << 41253c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg6); 41353c45f0cShuang lin 41453c45f0cShuang lin writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 | 41553c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_ENABLE | 41653c45f0cShuang lin (0 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) << 41753c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT, 41853c45f0cShuang lin &ddr_phy->ddrphy_reg9); 41953c45f0cShuang lin } else { 42053c45f0cShuang lin writel(CMD_DLL_BYPASS_DISABLE | HIGH_8BIT_DLL_BYPASS_DISABLE | 42153c45f0cShuang lin LOW_8BIT_DLL_BYPASS_DISABLE, &ddr_phy->ddrphy_reg2a); 42253c45f0cShuang lin 42353c45f0cShuang lin writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_0 | 42453c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_ENABLE | 42553c45f0cShuang lin (4 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) << 42653c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT, 42753c45f0cShuang lin &ddr_phy->ddrphy_reg6); 42853c45f0cShuang lin 42953c45f0cShuang lin writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 | 43053c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_ENABLE | 43153c45f0cShuang lin (4 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) << 43253c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT, 43353c45f0cShuang lin &ddr_phy->ddrphy_reg9); 43453c45f0cShuang lin } 43553c45f0cShuang lin 43653c45f0cShuang lin writel(CMD_SLAVE_DLL_NO_INVERSE_MODE | CMD_SLAVE_DLL_ENALBE | 43753c45f0cShuang lin (0 & CMD_TX_SLAVE_DLL_DELAY_MASK) << 43853c45f0cShuang lin CMD_TX_SLAVE_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg19); 43953c45f0cShuang lin 44053c45f0cShuang lin /* 45 degree delay */ 44153c45f0cShuang lin writel((DQS_DLL_45_DELAY & LEFT_CHN_RX_DQS_DELAY_TAP_MASK) << 44253c45f0cShuang lin LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg8); 44353c45f0cShuang lin writel((DQS_DLL_45_DELAY & RIGHT_CHN_RX_DQS_DELAY_TAP_MASK) << 44453c45f0cShuang lin RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg11); 44553c45f0cShuang lin } 44653c45f0cShuang lin 44753c45f0cShuang lin static void send_command(struct rk3036_ddr_pctl *pctl, 44853c45f0cShuang lin u32 rank, u32 cmd, u32 arg) 44953c45f0cShuang lin { 45053c45f0cShuang lin writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd); 45153c45f0cShuang lin rockchip_udelay(1); 45253c45f0cShuang lin while (readl(&pctl->mcmd) & START_CMD) 45353c45f0cShuang lin ; 45453c45f0cShuang lin } 45553c45f0cShuang lin 45653c45f0cShuang lin static void memory_init(struct rk3036_sdram_priv *priv) 45753c45f0cShuang lin { 45853c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 45953c45f0cShuang lin 46053c45f0cShuang lin send_command(pctl, 3, DESELECT_CMD, 0); 46153c45f0cShuang lin rockchip_udelay(1); 46253c45f0cShuang lin send_command(pctl, 3, PREA_CMD, 0); 46353c45f0cShuang lin send_command(pctl, 3, MRS_CMD, 46453c45f0cShuang lin (0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | 46553c45f0cShuang lin (ddr_timing.phy_timing.mr[2] & CMD_ADDR_MASK) << 46653c45f0cShuang lin CMD_ADDR_SHIFT); 46753c45f0cShuang lin 46853c45f0cShuang lin send_command(pctl, 3, MRS_CMD, 46953c45f0cShuang lin (0x03 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | 47053c45f0cShuang lin (ddr_timing.phy_timing.mr[3] & CMD_ADDR_MASK) << 47153c45f0cShuang lin CMD_ADDR_SHIFT); 47253c45f0cShuang lin 47353c45f0cShuang lin send_command(pctl, 3, MRS_CMD, 47453c45f0cShuang lin (0x01 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | 47553c45f0cShuang lin (ddr_timing.phy_timing.mr[1] & CMD_ADDR_MASK) << 47653c45f0cShuang lin CMD_ADDR_SHIFT); 47753c45f0cShuang lin 47853c45f0cShuang lin send_command(pctl, 3, MRS_CMD, 47953c45f0cShuang lin (0x00 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT | 48053c45f0cShuang lin (ddr_timing.phy_timing.mr[0] & CMD_ADDR_MASK) << 48153c45f0cShuang lin CMD_ADDR_SHIFT | DDR3_DLL_RESET); 48253c45f0cShuang lin 48353c45f0cShuang lin send_command(pctl, 3, ZQCL_CMD, 0); 48453c45f0cShuang lin } 48553c45f0cShuang lin 48653c45f0cShuang lin static void data_training(struct rk3036_sdram_priv *priv) 48753c45f0cShuang lin { 48853c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy; 48953c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 49053c45f0cShuang lin u32 value; 49153c45f0cShuang lin 49253c45f0cShuang lin /* disable auto refresh */ 49353c45f0cShuang lin value = readl(&pctl->trefi), 49453c45f0cShuang lin writel(0, &pctl->trefi); 49553c45f0cShuang lin 49653c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03, 49753c45f0cShuang lin DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_CAL_START); 49853c45f0cShuang lin 49953c45f0cShuang lin rockchip_udelay(1); 50053c45f0cShuang lin while ((readl(&ddr_phy->ddrphy_reg62) & CAL_DONE_MASK) != 50153c45f0cShuang lin (HIGH_8BIT_CAL_DONE | LOW_8BIT_CAL_DONE)) { 50253c45f0cShuang lin ; 50353c45f0cShuang lin } 50453c45f0cShuang lin 50553c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03, 50653c45f0cShuang lin DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_NO_CAL); 50753c45f0cShuang lin 50853c45f0cShuang lin /* 50953c45f0cShuang lin * since data training will take about 20us, so send some auto 51053c45f0cShuang lin * refresh(about 7.8us) to complement the lost time 51153c45f0cShuang lin */ 51253c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0); 51353c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0); 51453c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0); 51553c45f0cShuang lin 51653c45f0cShuang lin writel(value, &pctl->trefi); 51753c45f0cShuang lin } 51853c45f0cShuang lin 51953c45f0cShuang lin static void move_to_config_state(struct rk3036_sdram_priv *priv) 52053c45f0cShuang lin { 52153c45f0cShuang lin unsigned int state; 52253c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 52353c45f0cShuang lin 52453c45f0cShuang lin while (1) { 52553c45f0cShuang lin state = readl(&pctl->stat) & PCTL_STAT_MASK; 52653c45f0cShuang lin switch (state) { 52753c45f0cShuang lin case LOW_POWER: 52853c45f0cShuang lin writel(WAKEUP_STATE, &pctl->sctl); 52953c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) 53053c45f0cShuang lin != ACCESS) 53153c45f0cShuang lin ; 53253c45f0cShuang lin /* 53353c45f0cShuang lin * If at low power state, need wakeup first, and then 53453c45f0cShuang lin * enter the config, so fallthrough 53553c45f0cShuang lin */ 53653c45f0cShuang lin case ACCESS: 53753c45f0cShuang lin /* fallthrough */ 53853c45f0cShuang lin case INIT_MEM: 53953c45f0cShuang lin writel(CFG_STATE, &pctl->sctl); 54053c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) 54153c45f0cShuang lin ; 54253c45f0cShuang lin break; 54353c45f0cShuang lin case CONFIG: 54453c45f0cShuang lin return; 54553c45f0cShuang lin default: 54653c45f0cShuang lin break; 54753c45f0cShuang lin } 54853c45f0cShuang lin } 54953c45f0cShuang lin } 55053c45f0cShuang lin 55153c45f0cShuang lin static void move_to_access_state(struct rk3036_sdram_priv *priv) 55253c45f0cShuang lin { 55353c45f0cShuang lin unsigned int state; 55453c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 55553c45f0cShuang lin 55653c45f0cShuang lin while (1) { 55753c45f0cShuang lin state = readl(&pctl->stat) & PCTL_STAT_MASK; 55853c45f0cShuang lin switch (state) { 55953c45f0cShuang lin case LOW_POWER: 56053c45f0cShuang lin writel(WAKEUP_STATE, &pctl->sctl); 56153c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) 56253c45f0cShuang lin ; 56353c45f0cShuang lin break; 56453c45f0cShuang lin case INIT_MEM: 56553c45f0cShuang lin writel(CFG_STATE, &pctl->sctl); 56653c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG) 56753c45f0cShuang lin ; 56853c45f0cShuang lin /* fallthrough */ 56953c45f0cShuang lin case CONFIG: 57053c45f0cShuang lin writel(GO_STATE, &pctl->sctl); 57153c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS) 57253c45f0cShuang lin ; 57353c45f0cShuang lin break; 57453c45f0cShuang lin case ACCESS: 57553c45f0cShuang lin return; 57653c45f0cShuang lin default: 57753c45f0cShuang lin break; 57853c45f0cShuang lin } 57953c45f0cShuang lin } 58053c45f0cShuang lin } 58153c45f0cShuang lin 58253c45f0cShuang lin static void pctl_cfg(struct rk3036_sdram_priv *priv) 58353c45f0cShuang lin { 58453c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl; 58553c45f0cShuang lin u32 burst_len; 58653c45f0cShuang lin u32 reg; 58753c45f0cShuang lin 58853c45f0cShuang lin writel(DFI_INIT_START | DFI_DATA_BYTE_DISABLE_EN, &pctl->dfistcfg0); 58953c45f0cShuang lin writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, &pctl->dfistcfg1); 59053c45f0cShuang lin writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2); 59153c45f0cShuang lin writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN, 59253c45f0cShuang lin &pctl->dfilpcfg0); 59353c45f0cShuang lin 59453c45f0cShuang lin writel(1, &pctl->dfitphyupdtype0); 59553c45f0cShuang lin writel(0x0d, &pctl->dfitphyrdlat); 59653c45f0cShuang lin 59753c45f0cShuang lin /* cs0 and cs1 write odt enable */ 59853c45f0cShuang lin writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL), 59953c45f0cShuang lin &pctl->dfiodtcfg); 60053c45f0cShuang lin 60153c45f0cShuang lin /* odt write length */ 60253c45f0cShuang lin writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1); 60353c45f0cShuang lin 60453c45f0cShuang lin /* phyupd and ctrlupd disabled */ 60553c45f0cShuang lin writel(0, &pctl->dfiupdcfg); 60653c45f0cShuang lin 60753c45f0cShuang lin if ((ddr_timing.noc_timing.burstlen << 1) == 4) 60853c45f0cShuang lin burst_len = MEM_BL4; 60953c45f0cShuang lin else 61053c45f0cShuang lin burst_len = MEM_BL8; 61153c45f0cShuang lin 61253c45f0cShuang lin copy_to_reg(&pctl->togcnt1u, &ddr_timing.pctl_timing.togcnt1u, 61353c45f0cShuang lin sizeof(struct rk3036_pctl_timing)); 61453c45f0cShuang lin reg = readl(&pctl->tcl); 61553c45f0cShuang lin writel(reg - 3, &pctl->dfitrddataen); 61653c45f0cShuang lin reg = readl(&pctl->tcwl); 61753c45f0cShuang lin writel(reg - 1, &pctl->dfitphywrlat); 61853c45f0cShuang lin 61953c45f0cShuang lin writel(burst_len | (1 & TFAW_CFG_MASK) << TFAW_CFG_SHIFT | 62053c45f0cShuang lin PD_EXIT_SLOW_MODE | PD_ACTIVE_POWER_DOWN | 62153c45f0cShuang lin (0 & PD_IDLE_MASK) << PD_IDLE_SHIFT, 62253c45f0cShuang lin &pctl->mcfg); 62353c45f0cShuang lin 62453c45f0cShuang lin writel(RK_SETBITS(MSCH4_MAINDDR3), &priv->grf->soc_con2); 62553c45f0cShuang lin setbits_le32(&pctl->scfg, HW_LOW_POWER_EN); 62653c45f0cShuang lin } 62753c45f0cShuang lin 62853c45f0cShuang lin static void phy_cfg(struct rk3036_sdram_priv *priv) 62953c45f0cShuang lin { 63053c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy; 63153c45f0cShuang lin struct rk3036_service_sys *axi_bus = priv->axi_bus; 63253c45f0cShuang lin 63353c45f0cShuang lin writel(ddr_timing.noc_timing.noc_timing, &axi_bus->ddrtiming); 63453c45f0cShuang lin writel(0x3f, &axi_bus->readlatency); 63553c45f0cShuang lin 63653c45f0cShuang lin writel(MEMORY_SELECT_DDR3 | DQS_SQU_CAL_NORMAL_MODE, 63753c45f0cShuang lin &ddr_phy->ddrphy_reg2); 63853c45f0cShuang lin 63953c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg3, 1, ddr_timing.phy_timing.bl); 64053c45f0cShuang lin writel(ddr_timing.phy_timing.cl_al, &ddr_phy->ddrphy_reg4a); 64153c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg16); 64253c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg22); 64353c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg25); 64453c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg26); 64553c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg27); 64653c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg28); 64753c45f0cShuang lin } 64853c45f0cShuang lin 64953c45f0cShuang lin void dram_cfg_rbc(struct rk3036_sdram_priv *priv) 65053c45f0cShuang lin { 65153c45f0cShuang lin char noc_config; 65253c45f0cShuang lin int i = 0; 65353c45f0cShuang lin struct rk3036_ddr_config config = priv->ddr_config; 65453c45f0cShuang lin struct rk3036_service_sys *axi_bus = priv->axi_bus; 65553c45f0cShuang lin 65653c45f0cShuang lin move_to_config_state(priv); 65753c45f0cShuang lin 65853c45f0cShuang lin /* 2bit in BIT1, 2 */ 65953c45f0cShuang lin if (config.rank == 2) { 66053c45f0cShuang lin noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 | 66153c45f0cShuang lin 1 << 3 | (config.col - 10); 66253c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[9]) { 66353c45f0cShuang lin i = 9; 66453c45f0cShuang lin goto finish; 66553c45f0cShuang lin } else if (noc_config == ddr_cfg_2_rbc[10]) { 66653c45f0cShuang lin i = 10; 66753c45f0cShuang lin goto finish; 66853c45f0cShuang lin } 66953c45f0cShuang lin } 67053c45f0cShuang lin 67153c45f0cShuang lin noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 | 67253c45f0cShuang lin (config.col - 10); 67353c45f0cShuang lin 67453c45f0cShuang lin for (i = 0; i < sizeof(ddr_cfg_2_rbc); i++) { 67553c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[i]) 67653c45f0cShuang lin goto finish; 67753c45f0cShuang lin } 67853c45f0cShuang lin 67953c45f0cShuang lin /* bank: 1 bit in BIT6,7, 1bit in BIT1, 2 */ 68053c45f0cShuang lin noc_config = 1 << 6 | (config.cs0_row - 13) << 4 | 68153c45f0cShuang lin 2 << 1 | (config.col - 10); 68253c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[11]) { 68353c45f0cShuang lin i = 11; 68453c45f0cShuang lin goto finish; 68553c45f0cShuang lin } 68653c45f0cShuang lin 68753c45f0cShuang lin /* bank: 2bit in BIT6,7 */ 68853c45f0cShuang lin noc_config = (config.bank << 6) | (config.cs0_row - 13) << 4 | 68953c45f0cShuang lin (config.col - 10); 69053c45f0cShuang lin 69153c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[0]) 69253c45f0cShuang lin i = 0; 69353c45f0cShuang lin else if (noc_config == ddr_cfg_2_rbc[12]) 69453c45f0cShuang lin i = 12; 69553c45f0cShuang lin else if (noc_config == ddr_cfg_2_rbc[13]) 69653c45f0cShuang lin i = 13; 69753c45f0cShuang lin finish: 69853c45f0cShuang lin writel(i, &axi_bus->ddrconf); 69953c45f0cShuang lin move_to_access_state(priv); 70053c45f0cShuang lin } 70153c45f0cShuang lin 70253c45f0cShuang lin static void sdram_all_config(struct rk3036_sdram_priv *priv) 70353c45f0cShuang lin { 70453c45f0cShuang lin u32 os_reg = 0; 705e3906800Shuang lin u32 cs1_row = 0; 70653c45f0cShuang lin struct rk3036_ddr_config config = priv->ddr_config; 70753c45f0cShuang lin 708e3906800Shuang lin if (config.rank > 1) 709e3906800Shuang lin cs1_row = config.cs1_row - 13; 710e3906800Shuang lin 71153c45f0cShuang lin os_reg = config.ddr_type << DDR_TYPE_SHIFT | 71253c45f0cShuang lin 0 << DDR_CHN_CNT_SHIFT | 71353c45f0cShuang lin (config.rank - 1) << DDR_RANK_CNT_SHIFT | 71464a524b0SKever Yang (config.col - 9) << DDR_COL_SHIFT | 71553c45f0cShuang lin (config.bank == 3 ? 0 : 1) << DDR_BANK_SHIFT | 71653c45f0cShuang lin (config.cs0_row - 13) << DDR_CS0_ROW_SHIFT | 717e3906800Shuang lin cs1_row << DDR_CS1_ROW_SHIFT | 71864a524b0SKever Yang 1 << DDR_BW_SHIFT | 71964a524b0SKever Yang (2 >> config.bw) << DDR_DIE_BW_SHIFT; 72053c45f0cShuang lin writel(os_reg, &priv->grf->os_reg[1]); 72153c45f0cShuang lin } 72253c45f0cShuang lin 72353c45f0cShuang lin size_t sdram_size(void) 72453c45f0cShuang lin { 72553c45f0cShuang lin u32 size, os_reg, cs0_row, cs1_row, col, bank, rank; 72653c45f0cShuang lin struct rk3036_grf *grf = (void *)GRF_BASE; 72753c45f0cShuang lin 72853c45f0cShuang lin os_reg = readl(&grf->os_reg[1]); 72953c45f0cShuang lin 73053c45f0cShuang lin cs0_row = 13 + ((os_reg >> DDR_CS0_ROW_SHIFT) & DDR_CS0_ROW_MASK); 73153c45f0cShuang lin cs1_row = 13 + ((os_reg >> DDR_CS1_ROW_SHIFT) & DDR_CS1_ROW_MASK); 73253c45f0cShuang lin col = 9 + ((os_reg >> DDR_COL_SHIFT) & DDR_COL_MASK); 73353c45f0cShuang lin bank = 3 - ((os_reg >> DDR_BANK_SHIFT) & DDR_BANK_MASK); 73453c45f0cShuang lin rank = 1 + ((os_reg >> DDR_RANK_CNT_SHIFT) & DDR_RANK_CNT_MASK); 73553c45f0cShuang lin 73653c45f0cShuang lin /* row + col + bank + bw(rk3036 only support 16bit, so fix in 1) */ 73753c45f0cShuang lin size = 1 << (cs0_row + col + bank + 1); 73853c45f0cShuang lin 73953c45f0cShuang lin if (rank > 1) 74053c45f0cShuang lin size += size >> (cs0_row - cs1_row); 74153c45f0cShuang lin 74253c45f0cShuang lin return size; 74353c45f0cShuang lin } 74453c45f0cShuang lin 74553c45f0cShuang lin void sdram_init(void) 74653c45f0cShuang lin { 74753c45f0cShuang lin struct rk3036_sdram_priv sdram_priv; 74853c45f0cShuang lin 74953c45f0cShuang lin sdram_priv.cru = (void *)CRU_BASE; 75053c45f0cShuang lin sdram_priv.grf = (void *)GRF_BASE; 75153c45f0cShuang lin sdram_priv.phy = (void *)DDR_PHY_BASE; 75253c45f0cShuang lin sdram_priv.pctl = (void *)DDR_PCTL_BASE; 75353c45f0cShuang lin sdram_priv.axi_bus = (void *)CPU_AXI_BUS_BASE; 75453c45f0cShuang lin 75553c45f0cShuang lin get_ddr_config(&sdram_priv.ddr_config); 75653c45f0cShuang lin sdram_all_config(&sdram_priv); 75753c45f0cShuang lin rkdclk_init(&sdram_priv); 75853c45f0cShuang lin phy_pctrl_reset(&sdram_priv); 75953c45f0cShuang lin phy_dll_bypass_set(&sdram_priv, ddr_timing.freq); 76053c45f0cShuang lin pctl_cfg(&sdram_priv); 76153c45f0cShuang lin phy_cfg(&sdram_priv); 76253c45f0cShuang lin writel(POWER_UP_START, &sdram_priv.pctl->powctl); 76353c45f0cShuang lin while (!(readl(&sdram_priv.pctl->powstat) & POWER_UP_DONE)) 76453c45f0cShuang lin ; 76553c45f0cShuang lin memory_init(&sdram_priv); 76653c45f0cShuang lin move_to_config_state(&sdram_priv); 76753c45f0cShuang lin data_training(&sdram_priv); 76853c45f0cShuang lin move_to_access_state(&sdram_priv); 76953c45f0cShuang lin dram_cfg_rbc(&sdram_priv); 77053c45f0cShuang lin } 771