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