1*7ff02556SKever Yang // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
253c45f0cShuang lin /*
3*7ff02556SKever Yang * (C) Copyright 2015 Rockchip Electronics Co., Ltd
453c45f0cShuang lin */
553c45f0cShuang lin #include <common.h>
653c45f0cShuang lin #include <asm/io.h>
753c45f0cShuang lin #include <asm/types.h>
853c45f0cShuang lin #include <asm/arch/cru_rk3036.h>
953c45f0cShuang lin #include <asm/arch/grf_rk3036.h>
1053c45f0cShuang lin #include <asm/arch/hardware.h>
1153c45f0cShuang lin #include <asm/arch/sdram_rk3036.h>
1253c45f0cShuang lin #include <asm/arch/timer.h>
1353c45f0cShuang lin #include <asm/arch/uart.h>
1453c45f0cShuang lin
1553c45f0cShuang lin /*
1653c45f0cShuang lin * we can not fit the code to access the device tree in SPL
1753c45f0cShuang lin * (due to 4K SRAM size limits), so these are hard-coded
1853c45f0cShuang lin */
1953c45f0cShuang lin #define CRU_BASE 0x20000000
2053c45f0cShuang lin #define GRF_BASE 0x20008000
2153c45f0cShuang lin #define DDR_PHY_BASE 0x2000a000
2253c45f0cShuang lin #define DDR_PCTL_BASE 0x20004000
2353c45f0cShuang lin #define CPU_AXI_BUS_BASE 0x10128000
2453c45f0cShuang lin
2553c45f0cShuang lin struct rk3036_sdram_priv {
2653c45f0cShuang lin struct rk3036_cru *cru;
2753c45f0cShuang lin struct rk3036_grf *grf;
2853c45f0cShuang lin struct rk3036_ddr_phy *phy;
2953c45f0cShuang lin struct rk3036_ddr_pctl *pctl;
3053c45f0cShuang lin struct rk3036_service_sys *axi_bus;
3153c45f0cShuang lin
3253c45f0cShuang lin /* ddr die config */
3353c45f0cShuang lin struct rk3036_ddr_config ddr_config;
3453c45f0cShuang lin };
3553c45f0cShuang lin
36faa75ad9SKever Yang /*
37faa75ad9SKever Yang * use integer mode, dpll output 792MHz and ddr get 396MHz
3853c45f0cShuang lin * refdiv, fbdiv, postdiv1, postdiv2
3953c45f0cShuang lin */
40faa75ad9SKever Yang const struct pll_div dpll_init_cfg = {1, 66, 2, 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
rkdclk_init(struct rk3036_sdram_priv * priv)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 */
332731cafecSKever Yang rk_clrsetreg(&priv->cru->cru_mode_con, DPLL_MODE_MASK,
33353c45f0cShuang lin DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
33453c45f0cShuang lin
33553c45f0cShuang lin /* use integer mode */
336fd1f80aaSKever Yang rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
33753c45f0cShuang lin
33853c45f0cShuang lin rk_clrsetreg(&pll->con0,
339731cafecSKever Yang PLL_POSTDIV1_MASK | PLL_FBDIV_MASK,
34053c45f0cShuang lin (dpll_init_cfg.postdiv1 << PLL_POSTDIV1_SHIFT) |
34153c45f0cShuang lin dpll_init_cfg.fbdiv);
342731cafecSKever Yang rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK,
34353c45f0cShuang lin (dpll_init_cfg.postdiv2 << PLL_POSTDIV2_SHIFT |
34453c45f0cShuang lin dpll_init_cfg.refdiv << PLL_REFDIV_SHIFT));
34553c45f0cShuang lin
34653c45f0cShuang lin /* waiting for pll lock */
34753c45f0cShuang lin while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))
34853c45f0cShuang lin rockchip_udelay(1);
34953c45f0cShuang lin
35053c45f0cShuang lin /* PLL enter normal-mode */
351731cafecSKever Yang rk_clrsetreg(&priv->cru->cru_mode_con, DPLL_MODE_MASK,
35253c45f0cShuang lin DPLL_MODE_NORM << DPLL_MODE_SHIFT);
35353c45f0cShuang lin }
35453c45f0cShuang lin
copy_to_reg(u32 * dest,const u32 * src,u32 n)35553c45f0cShuang lin static void copy_to_reg(u32 *dest, const u32 *src, u32 n)
35653c45f0cShuang lin {
35753c45f0cShuang lin int i;
35853c45f0cShuang lin
35953c45f0cShuang lin for (i = 0; i < n / sizeof(u32); i++) {
36053c45f0cShuang lin writel(*src, dest);
36153c45f0cShuang lin src++;
36253c45f0cShuang lin dest++;
36353c45f0cShuang lin }
36453c45f0cShuang lin }
36553c45f0cShuang lin
phy_pctrl_reset(struct rk3036_sdram_priv * priv)36653c45f0cShuang lin void phy_pctrl_reset(struct rk3036_sdram_priv *priv)
36753c45f0cShuang lin {
36853c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy;
36953c45f0cShuang lin
37053c45f0cShuang lin rk_clrsetreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
37153c45f0cShuang lin 1 << DDRCTRL_SRST_SHIFT | 1 << DDRPHY_PSRST_SHIFT |
37253c45f0cShuang lin 1 << DDRPHY_SRST_SHIFT,
37353c45f0cShuang lin 1 << DDRCTRL_PSRST_SHIFT | 1 << DDRCTRL_SRST_SHIFT |
37453c45f0cShuang lin 1 << DDRPHY_PSRST_SHIFT | 1 << DDRPHY_SRST_SHIFT);
37553c45f0cShuang lin
37653c45f0cShuang lin rockchip_udelay(10);
37753c45f0cShuang lin
37853c45f0cShuang lin rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRPHY_PSRST_SHIFT |
37953c45f0cShuang lin 1 << DDRPHY_SRST_SHIFT);
38053c45f0cShuang lin rockchip_udelay(10);
38153c45f0cShuang lin
38253c45f0cShuang lin rk_clrreg(&priv->cru->cru_softrst_con[5], 1 << DDRCTRL_PSRST_SHIFT |
38353c45f0cShuang lin 1 << DDRCTRL_SRST_SHIFT);
38453c45f0cShuang lin rockchip_udelay(10);
38553c45f0cShuang lin
38653c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg1,
38753c45f0cShuang lin SOFT_RESET_MASK << SOFT_RESET_SHIFT,
38853c45f0cShuang lin 0 << SOFT_RESET_SHIFT);
38953c45f0cShuang lin rockchip_udelay(10);
39053c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg1,
39153c45f0cShuang lin SOFT_RESET_MASK << SOFT_RESET_SHIFT,
39253c45f0cShuang lin 3 << SOFT_RESET_SHIFT);
39353c45f0cShuang lin
39453c45f0cShuang lin rockchip_udelay(1);
39553c45f0cShuang lin }
39653c45f0cShuang lin
phy_dll_bypass_set(struct rk3036_sdram_priv * priv,unsigned int freq)39753c45f0cShuang lin void phy_dll_bypass_set(struct rk3036_sdram_priv *priv, unsigned int freq)
39853c45f0cShuang lin {
39953c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy;
40053c45f0cShuang lin
40153c45f0cShuang lin if (freq < ddr_timing.freq) {
40253c45f0cShuang lin writel(CMD_DLL_BYPASS | HIGH_8BIT_DLL_BYPASS |
40353c45f0cShuang lin LOW_8BIT_DLL_BYPASS, &ddr_phy->ddrphy_reg2a);
40453c45f0cShuang lin
40553c45f0cShuang lin writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_90 |
40653c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_ENABLE |
40753c45f0cShuang lin (0 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) <<
40853c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg6);
40953c45f0cShuang lin
41053c45f0cShuang lin writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_90 |
41153c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_ENABLE |
41253c45f0cShuang lin (0 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) <<
41353c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT,
41453c45f0cShuang lin &ddr_phy->ddrphy_reg9);
41553c45f0cShuang lin } else {
41653c45f0cShuang lin writel(CMD_DLL_BYPASS_DISABLE | HIGH_8BIT_DLL_BYPASS_DISABLE |
41753c45f0cShuang lin LOW_8BIT_DLL_BYPASS_DISABLE, &ddr_phy->ddrphy_reg2a);
41853c45f0cShuang lin
41953c45f0cShuang lin writel(LEFT_CHN_TX_DQ_PHASE_BYPASS_0 |
42053c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_ENABLE |
42153c45f0cShuang lin (4 & LEFT_CHN_TX_DQ_DLL_DELAY_MASK) <<
42253c45f0cShuang lin LEFT_CHN_TX_DQ_DLL_DELAY_SHIFT,
42353c45f0cShuang lin &ddr_phy->ddrphy_reg6);
42453c45f0cShuang lin
42553c45f0cShuang lin writel(RIGHT_CHN_TX_DQ_PHASE_BYPASS_0 |
42653c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_ENABLE |
42753c45f0cShuang lin (4 & RIGHT_CHN_TX_DQ_DLL_DELAY_MASK) <<
42853c45f0cShuang lin RIGHT_CHN_TX_DQ_DLL_DELAY_SHIFT,
42953c45f0cShuang lin &ddr_phy->ddrphy_reg9);
43053c45f0cShuang lin }
43153c45f0cShuang lin
43253c45f0cShuang lin writel(CMD_SLAVE_DLL_NO_INVERSE_MODE | CMD_SLAVE_DLL_ENALBE |
43353c45f0cShuang lin (0 & CMD_TX_SLAVE_DLL_DELAY_MASK) <<
43453c45f0cShuang lin CMD_TX_SLAVE_DLL_DELAY_SHIFT, &ddr_phy->ddrphy_reg19);
43553c45f0cShuang lin
43653c45f0cShuang lin /* 45 degree delay */
43753c45f0cShuang lin writel((DQS_DLL_45_DELAY & LEFT_CHN_RX_DQS_DELAY_TAP_MASK) <<
43853c45f0cShuang lin LEFT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg8);
43953c45f0cShuang lin writel((DQS_DLL_45_DELAY & RIGHT_CHN_RX_DQS_DELAY_TAP_MASK) <<
44053c45f0cShuang lin RIGHT_CHN_RX_DQS_DELAY_TAP_SHIFT, &ddr_phy->ddrphy_reg11);
44153c45f0cShuang lin }
44253c45f0cShuang lin
send_command(struct rk3036_ddr_pctl * pctl,u32 rank,u32 cmd,u32 arg)44353c45f0cShuang lin static void send_command(struct rk3036_ddr_pctl *pctl,
44453c45f0cShuang lin u32 rank, u32 cmd, u32 arg)
44553c45f0cShuang lin {
44653c45f0cShuang lin writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd);
44753c45f0cShuang lin rockchip_udelay(1);
44853c45f0cShuang lin while (readl(&pctl->mcmd) & START_CMD)
44953c45f0cShuang lin ;
45053c45f0cShuang lin }
45153c45f0cShuang lin
memory_init(struct rk3036_sdram_priv * priv)45253c45f0cShuang lin static void memory_init(struct rk3036_sdram_priv *priv)
45353c45f0cShuang lin {
45453c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl;
45553c45f0cShuang lin
45653c45f0cShuang lin send_command(pctl, 3, DESELECT_CMD, 0);
45753c45f0cShuang lin rockchip_udelay(1);
45853c45f0cShuang lin send_command(pctl, 3, PREA_CMD, 0);
45953c45f0cShuang lin send_command(pctl, 3, MRS_CMD,
46053c45f0cShuang lin (0x02 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
46153c45f0cShuang lin (ddr_timing.phy_timing.mr[2] & CMD_ADDR_MASK) <<
46253c45f0cShuang lin CMD_ADDR_SHIFT);
46353c45f0cShuang lin
46453c45f0cShuang lin send_command(pctl, 3, MRS_CMD,
46553c45f0cShuang lin (0x03 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
46653c45f0cShuang lin (ddr_timing.phy_timing.mr[3] & CMD_ADDR_MASK) <<
46753c45f0cShuang lin CMD_ADDR_SHIFT);
46853c45f0cShuang lin
46953c45f0cShuang lin send_command(pctl, 3, MRS_CMD,
47053c45f0cShuang lin (0x01 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
47153c45f0cShuang lin (ddr_timing.phy_timing.mr[1] & CMD_ADDR_MASK) <<
47253c45f0cShuang lin CMD_ADDR_SHIFT);
47353c45f0cShuang lin
47453c45f0cShuang lin send_command(pctl, 3, MRS_CMD,
47553c45f0cShuang lin (0x00 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
47653c45f0cShuang lin (ddr_timing.phy_timing.mr[0] & CMD_ADDR_MASK) <<
47753c45f0cShuang lin CMD_ADDR_SHIFT | DDR3_DLL_RESET);
47853c45f0cShuang lin
47953c45f0cShuang lin send_command(pctl, 3, ZQCL_CMD, 0);
48053c45f0cShuang lin }
48153c45f0cShuang lin
data_training(struct rk3036_sdram_priv * priv)48253c45f0cShuang lin static void data_training(struct rk3036_sdram_priv *priv)
48353c45f0cShuang lin {
48453c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy;
48553c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl;
48653c45f0cShuang lin u32 value;
48753c45f0cShuang lin
48853c45f0cShuang lin /* disable auto refresh */
48953c45f0cShuang lin value = readl(&pctl->trefi),
49053c45f0cShuang lin writel(0, &pctl->trefi);
49153c45f0cShuang lin
49253c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03,
49353c45f0cShuang lin DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_CAL_START);
49453c45f0cShuang lin
49553c45f0cShuang lin rockchip_udelay(1);
49653c45f0cShuang lin while ((readl(&ddr_phy->ddrphy_reg62) & CAL_DONE_MASK) !=
49753c45f0cShuang lin (HIGH_8BIT_CAL_DONE | LOW_8BIT_CAL_DONE)) {
49853c45f0cShuang lin ;
49953c45f0cShuang lin }
50053c45f0cShuang lin
50153c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg2, 0x03,
50253c45f0cShuang lin DQS_SQU_CAL_NORMAL_MODE | DQS_SQU_NO_CAL);
50353c45f0cShuang lin
50453c45f0cShuang lin /*
50553c45f0cShuang lin * since data training will take about 20us, so send some auto
50653c45f0cShuang lin * refresh(about 7.8us) to complement the lost time
50753c45f0cShuang lin */
50853c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0);
50953c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0);
51053c45f0cShuang lin send_command(pctl, 3, REF_CMD, 0);
51153c45f0cShuang lin
51253c45f0cShuang lin writel(value, &pctl->trefi);
51353c45f0cShuang lin }
51453c45f0cShuang lin
move_to_config_state(struct rk3036_sdram_priv * priv)51553c45f0cShuang lin static void move_to_config_state(struct rk3036_sdram_priv *priv)
51653c45f0cShuang lin {
51753c45f0cShuang lin unsigned int state;
51853c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl;
51953c45f0cShuang lin
52053c45f0cShuang lin while (1) {
52153c45f0cShuang lin state = readl(&pctl->stat) & PCTL_STAT_MASK;
52253c45f0cShuang lin switch (state) {
52353c45f0cShuang lin case LOW_POWER:
52453c45f0cShuang lin writel(WAKEUP_STATE, &pctl->sctl);
52553c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK)
52653c45f0cShuang lin != ACCESS)
52753c45f0cShuang lin ;
52853c45f0cShuang lin /*
52953c45f0cShuang lin * If at low power state, need wakeup first, and then
53053c45f0cShuang lin * enter the config, so fallthrough
53153c45f0cShuang lin */
53253c45f0cShuang lin case ACCESS:
53353c45f0cShuang lin /* fallthrough */
53453c45f0cShuang lin case INIT_MEM:
53553c45f0cShuang lin writel(CFG_STATE, &pctl->sctl);
53653c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG)
53753c45f0cShuang lin ;
53853c45f0cShuang lin break;
53953c45f0cShuang lin case CONFIG:
54053c45f0cShuang lin return;
54153c45f0cShuang lin default:
54253c45f0cShuang lin break;
54353c45f0cShuang lin }
54453c45f0cShuang lin }
54553c45f0cShuang lin }
54653c45f0cShuang lin
move_to_access_state(struct rk3036_sdram_priv * priv)54753c45f0cShuang lin static void move_to_access_state(struct rk3036_sdram_priv *priv)
54853c45f0cShuang lin {
54953c45f0cShuang lin unsigned int state;
55053c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl;
55153c45f0cShuang lin
55253c45f0cShuang lin while (1) {
55353c45f0cShuang lin state = readl(&pctl->stat) & PCTL_STAT_MASK;
55453c45f0cShuang lin switch (state) {
55553c45f0cShuang lin case LOW_POWER:
55653c45f0cShuang lin writel(WAKEUP_STATE, &pctl->sctl);
55753c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS)
55853c45f0cShuang lin ;
55953c45f0cShuang lin break;
56053c45f0cShuang lin case INIT_MEM:
56153c45f0cShuang lin writel(CFG_STATE, &pctl->sctl);
56253c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != CONFIG)
56353c45f0cShuang lin ;
56453c45f0cShuang lin /* fallthrough */
56553c45f0cShuang lin case CONFIG:
56653c45f0cShuang lin writel(GO_STATE, &pctl->sctl);
56753c45f0cShuang lin while ((readl(&pctl->stat) & PCTL_STAT_MASK) != ACCESS)
56853c45f0cShuang lin ;
56953c45f0cShuang lin break;
57053c45f0cShuang lin case ACCESS:
57153c45f0cShuang lin return;
57253c45f0cShuang lin default:
57353c45f0cShuang lin break;
57453c45f0cShuang lin }
57553c45f0cShuang lin }
57653c45f0cShuang lin }
57753c45f0cShuang lin
pctl_cfg(struct rk3036_sdram_priv * priv)57853c45f0cShuang lin static void pctl_cfg(struct rk3036_sdram_priv *priv)
57953c45f0cShuang lin {
58053c45f0cShuang lin struct rk3036_ddr_pctl *pctl = priv->pctl;
58153c45f0cShuang lin u32 burst_len;
58253c45f0cShuang lin u32 reg;
58353c45f0cShuang lin
58453c45f0cShuang lin writel(DFI_INIT_START | DFI_DATA_BYTE_DISABLE_EN, &pctl->dfistcfg0);
58553c45f0cShuang lin writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, &pctl->dfistcfg1);
58653c45f0cShuang lin writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2);
58753c45f0cShuang lin writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN,
58853c45f0cShuang lin &pctl->dfilpcfg0);
58953c45f0cShuang lin
59053c45f0cShuang lin writel(1, &pctl->dfitphyupdtype0);
59153c45f0cShuang lin writel(0x0d, &pctl->dfitphyrdlat);
59253c45f0cShuang lin
59353c45f0cShuang lin /* cs0 and cs1 write odt enable */
59453c45f0cShuang lin writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL),
59553c45f0cShuang lin &pctl->dfiodtcfg);
59653c45f0cShuang lin
59753c45f0cShuang lin /* odt write length */
59853c45f0cShuang lin writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1);
59953c45f0cShuang lin
60053c45f0cShuang lin /* phyupd and ctrlupd disabled */
60153c45f0cShuang lin writel(0, &pctl->dfiupdcfg);
60253c45f0cShuang lin
60353c45f0cShuang lin if ((ddr_timing.noc_timing.burstlen << 1) == 4)
60453c45f0cShuang lin burst_len = MEM_BL4;
60553c45f0cShuang lin else
60653c45f0cShuang lin burst_len = MEM_BL8;
60753c45f0cShuang lin
60853c45f0cShuang lin copy_to_reg(&pctl->togcnt1u, &ddr_timing.pctl_timing.togcnt1u,
60953c45f0cShuang lin sizeof(struct rk3036_pctl_timing));
61053c45f0cShuang lin reg = readl(&pctl->tcl);
61153c45f0cShuang lin writel(reg - 3, &pctl->dfitrddataen);
61253c45f0cShuang lin reg = readl(&pctl->tcwl);
61353c45f0cShuang lin writel(reg - 1, &pctl->dfitphywrlat);
61453c45f0cShuang lin
61553c45f0cShuang lin writel(burst_len | (1 & TFAW_CFG_MASK) << TFAW_CFG_SHIFT |
61653c45f0cShuang lin PD_EXIT_SLOW_MODE | PD_ACTIVE_POWER_DOWN |
61753c45f0cShuang lin (0 & PD_IDLE_MASK) << PD_IDLE_SHIFT,
61853c45f0cShuang lin &pctl->mcfg);
61953c45f0cShuang lin
62053c45f0cShuang lin writel(RK_SETBITS(MSCH4_MAINDDR3), &priv->grf->soc_con2);
62153c45f0cShuang lin setbits_le32(&pctl->scfg, HW_LOW_POWER_EN);
62253c45f0cShuang lin }
62353c45f0cShuang lin
phy_cfg(struct rk3036_sdram_priv * priv)62453c45f0cShuang lin static void phy_cfg(struct rk3036_sdram_priv *priv)
62553c45f0cShuang lin {
62653c45f0cShuang lin struct rk3036_ddr_phy *ddr_phy = priv->phy;
62753c45f0cShuang lin struct rk3036_service_sys *axi_bus = priv->axi_bus;
62853c45f0cShuang lin
62953c45f0cShuang lin writel(ddr_timing.noc_timing.noc_timing, &axi_bus->ddrtiming);
63053c45f0cShuang lin writel(0x3f, &axi_bus->readlatency);
63153c45f0cShuang lin
63253c45f0cShuang lin writel(MEMORY_SELECT_DDR3 | DQS_SQU_CAL_NORMAL_MODE,
63353c45f0cShuang lin &ddr_phy->ddrphy_reg2);
63453c45f0cShuang lin
63553c45f0cShuang lin clrsetbits_le32(&ddr_phy->ddrphy_reg3, 1, ddr_timing.phy_timing.bl);
63653c45f0cShuang lin writel(ddr_timing.phy_timing.cl_al, &ddr_phy->ddrphy_reg4a);
63753c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg16);
63853c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg22);
63953c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg25);
64053c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RON_44OHM), &ddr_phy->ddrphy_reg26);
64153c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg27);
64253c45f0cShuang lin writel(PHY_DRV_ODT_SET(PHY_RTT_216OHM), &ddr_phy->ddrphy_reg28);
64353c45f0cShuang lin }
64453c45f0cShuang lin
dram_cfg_rbc(struct rk3036_sdram_priv * priv)64553c45f0cShuang lin void dram_cfg_rbc(struct rk3036_sdram_priv *priv)
64653c45f0cShuang lin {
64753c45f0cShuang lin char noc_config;
64853c45f0cShuang lin int i = 0;
64953c45f0cShuang lin struct rk3036_ddr_config config = priv->ddr_config;
65053c45f0cShuang lin struct rk3036_service_sys *axi_bus = priv->axi_bus;
65153c45f0cShuang lin
65253c45f0cShuang lin move_to_config_state(priv);
65353c45f0cShuang lin
65453c45f0cShuang lin /* 2bit in BIT1, 2 */
65553c45f0cShuang lin if (config.rank == 2) {
65653c45f0cShuang lin noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 |
65753c45f0cShuang lin 1 << 3 | (config.col - 10);
65853c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[9]) {
65953c45f0cShuang lin i = 9;
66053c45f0cShuang lin goto finish;
66153c45f0cShuang lin } else if (noc_config == ddr_cfg_2_rbc[10]) {
66253c45f0cShuang lin i = 10;
66353c45f0cShuang lin goto finish;
66453c45f0cShuang lin }
66553c45f0cShuang lin }
66653c45f0cShuang lin
66753c45f0cShuang lin noc_config = (config.cs0_row - 13) << 4 | config.bank << 1 |
66853c45f0cShuang lin (config.col - 10);
66953c45f0cShuang lin
67053c45f0cShuang lin for (i = 0; i < sizeof(ddr_cfg_2_rbc); i++) {
67153c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[i])
67253c45f0cShuang lin goto finish;
67353c45f0cShuang lin }
67453c45f0cShuang lin
67553c45f0cShuang lin /* bank: 1 bit in BIT6,7, 1bit in BIT1, 2 */
67653c45f0cShuang lin noc_config = 1 << 6 | (config.cs0_row - 13) << 4 |
67753c45f0cShuang lin 2 << 1 | (config.col - 10);
67853c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[11]) {
67953c45f0cShuang lin i = 11;
68053c45f0cShuang lin goto finish;
68153c45f0cShuang lin }
68253c45f0cShuang lin
68353c45f0cShuang lin /* bank: 2bit in BIT6,7 */
68453c45f0cShuang lin noc_config = (config.bank << 6) | (config.cs0_row - 13) << 4 |
68553c45f0cShuang lin (config.col - 10);
68653c45f0cShuang lin
68753c45f0cShuang lin if (noc_config == ddr_cfg_2_rbc[0])
68853c45f0cShuang lin i = 0;
68953c45f0cShuang lin else if (noc_config == ddr_cfg_2_rbc[12])
69053c45f0cShuang lin i = 12;
69153c45f0cShuang lin else if (noc_config == ddr_cfg_2_rbc[13])
69253c45f0cShuang lin i = 13;
69353c45f0cShuang lin finish:
69453c45f0cShuang lin writel(i, &axi_bus->ddrconf);
69553c45f0cShuang lin move_to_access_state(priv);
69653c45f0cShuang lin }
69753c45f0cShuang lin
sdram_all_config(struct rk3036_sdram_priv * priv)69853c45f0cShuang lin static void sdram_all_config(struct rk3036_sdram_priv *priv)
69953c45f0cShuang lin {
70053c45f0cShuang lin u32 os_reg = 0;
701e3906800Shuang lin u32 cs1_row = 0;
70253c45f0cShuang lin struct rk3036_ddr_config config = priv->ddr_config;
70353c45f0cShuang lin
704e3906800Shuang lin if (config.rank > 1)
705e3906800Shuang lin cs1_row = config.cs1_row - 13;
706e3906800Shuang lin
70753c45f0cShuang lin os_reg = config.ddr_type << DDR_TYPE_SHIFT |
70853c45f0cShuang lin 0 << DDR_CHN_CNT_SHIFT |
70953c45f0cShuang lin (config.rank - 1) << DDR_RANK_CNT_SHIFT |
71064a524b0SKever Yang (config.col - 9) << DDR_COL_SHIFT |
71153c45f0cShuang lin (config.bank == 3 ? 0 : 1) << DDR_BANK_SHIFT |
71253c45f0cShuang lin (config.cs0_row - 13) << DDR_CS0_ROW_SHIFT |
713e3906800Shuang lin cs1_row << DDR_CS1_ROW_SHIFT |
71464a524b0SKever Yang 1 << DDR_BW_SHIFT |
71564a524b0SKever Yang (2 >> config.bw) << DDR_DIE_BW_SHIFT;
71653c45f0cShuang lin writel(os_reg, &priv->grf->os_reg[1]);
71753c45f0cShuang lin }
71853c45f0cShuang lin
sdram_size(void)71953c45f0cShuang lin size_t sdram_size(void)
72053c45f0cShuang lin {
72153c45f0cShuang lin u32 size, os_reg, cs0_row, cs1_row, col, bank, rank;
72253c45f0cShuang lin struct rk3036_grf *grf = (void *)GRF_BASE;
72353c45f0cShuang lin
72453c45f0cShuang lin os_reg = readl(&grf->os_reg[1]);
72553c45f0cShuang lin
72653c45f0cShuang lin cs0_row = 13 + ((os_reg >> DDR_CS0_ROW_SHIFT) & DDR_CS0_ROW_MASK);
72753c45f0cShuang lin cs1_row = 13 + ((os_reg >> DDR_CS1_ROW_SHIFT) & DDR_CS1_ROW_MASK);
72853c45f0cShuang lin col = 9 + ((os_reg >> DDR_COL_SHIFT) & DDR_COL_MASK);
72953c45f0cShuang lin bank = 3 - ((os_reg >> DDR_BANK_SHIFT) & DDR_BANK_MASK);
73053c45f0cShuang lin rank = 1 + ((os_reg >> DDR_RANK_CNT_SHIFT) & DDR_RANK_CNT_MASK);
73153c45f0cShuang lin
73253c45f0cShuang lin /* row + col + bank + bw(rk3036 only support 16bit, so fix in 1) */
73353c45f0cShuang lin size = 1 << (cs0_row + col + bank + 1);
73453c45f0cShuang lin
73553c45f0cShuang lin if (rank > 1)
73653c45f0cShuang lin size += size >> (cs0_row - cs1_row);
73753c45f0cShuang lin
73853c45f0cShuang lin return size;
73953c45f0cShuang lin }
74053c45f0cShuang lin
sdram_init(void)74153c45f0cShuang lin void sdram_init(void)
74253c45f0cShuang lin {
74353c45f0cShuang lin struct rk3036_sdram_priv sdram_priv;
74453c45f0cShuang lin
74553c45f0cShuang lin sdram_priv.cru = (void *)CRU_BASE;
74653c45f0cShuang lin sdram_priv.grf = (void *)GRF_BASE;
74753c45f0cShuang lin sdram_priv.phy = (void *)DDR_PHY_BASE;
74853c45f0cShuang lin sdram_priv.pctl = (void *)DDR_PCTL_BASE;
74953c45f0cShuang lin sdram_priv.axi_bus = (void *)CPU_AXI_BUS_BASE;
75053c45f0cShuang lin
75153c45f0cShuang lin get_ddr_config(&sdram_priv.ddr_config);
75253c45f0cShuang lin sdram_all_config(&sdram_priv);
75353c45f0cShuang lin rkdclk_init(&sdram_priv);
75453c45f0cShuang lin phy_pctrl_reset(&sdram_priv);
75553c45f0cShuang lin phy_dll_bypass_set(&sdram_priv, ddr_timing.freq);
75653c45f0cShuang lin pctl_cfg(&sdram_priv);
75753c45f0cShuang lin phy_cfg(&sdram_priv);
75853c45f0cShuang lin writel(POWER_UP_START, &sdram_priv.pctl->powctl);
75953c45f0cShuang lin while (!(readl(&sdram_priv.pctl->powstat) & POWER_UP_DONE))
76053c45f0cShuang lin ;
76153c45f0cShuang lin memory_init(&sdram_priv);
76253c45f0cShuang lin move_to_config_state(&sdram_priv);
76353c45f0cShuang lin data_training(&sdram_priv);
76453c45f0cShuang lin move_to_access_state(&sdram_priv);
76553c45f0cShuang lin dram_cfg_rbc(&sdram_priv);
76653c45f0cShuang lin }
767