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