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