1b86c816cSZhihuan He // SPDX-License-Identifier: GPL-2.0+
224b30f4fSZhihuan He /*
3b86c816cSZhihuan He * Copyright (C) 2020 Rockchip Electronics Co., Ltd
424b30f4fSZhihuan He */
5b86c816cSZhihuan He
624b30f4fSZhihuan He #include <common.h>
7*19d63b30SZhihuan He
8*19d63b30SZhihuan He #if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
9b86c816cSZhihuan He #include <debug_uart.h>
1024b30f4fSZhihuan He #include <dm.h>
1124b30f4fSZhihuan He #include <dm/root.h>
1224b30f4fSZhihuan He #include <dt-structs.h>
1324b30f4fSZhihuan He #include <ram.h>
1424b30f4fSZhihuan He #include <regmap.h>
1524b30f4fSZhihuan He #include <asm/io.h>
1624b30f4fSZhihuan He #include <asm/types.h>
1724b30f4fSZhihuan He #include <asm/arch/hardware.h>
1824b30f4fSZhihuan He #include <asm/arch/sdram_rv1108_pctl_phy.h>
1924b30f4fSZhihuan He #include <asm/arch/timer.h>
20e1f97ec3SYouMin Chen #include <asm/arch/sdram.h>
2124b30f4fSZhihuan He
2224b30f4fSZhihuan He #if defined(CONFIG_ROCKCHIP_RV1108)
2324b30f4fSZhihuan He #include <asm/arch/sdram_rv1108.h>
2424b30f4fSZhihuan He #elif defined(CONFIG_ROCKCHIP_RK3308)
2524b30f4fSZhihuan He #include <asm/arch/sdram_rk3308.h>
2624b30f4fSZhihuan He #endif
2724b30f4fSZhihuan He
2824b30f4fSZhihuan He /*
2924b30f4fSZhihuan He * we can not fit the code to access the device tree in SPL
3024b30f4fSZhihuan He * (due to 6K SRAM size limits), so these are hard-coded
3124b30f4fSZhihuan He */
3224b30f4fSZhihuan He
copy_to_reg(u32 * dest,const u32 * src,u32 n)33b86c816cSZhihuan He void copy_to_reg(u32 *dest, const u32 *src, u32 n)
3424b30f4fSZhihuan He {
3524b30f4fSZhihuan He int i;
3624b30f4fSZhihuan He
3724b30f4fSZhihuan He for (i = 0; i < n / sizeof(u32); i++) {
3824b30f4fSZhihuan He writel(*src, dest);
3924b30f4fSZhihuan He src++;
4024b30f4fSZhihuan He dest++;
4124b30f4fSZhihuan He }
4224b30f4fSZhihuan He }
4324b30f4fSZhihuan He
phy_pctrl_reset(struct dram_info * priv)4424b30f4fSZhihuan He static void phy_pctrl_reset(struct dram_info *priv)
4524b30f4fSZhihuan He {
4624b30f4fSZhihuan He phy_pctrl_reset_cru(priv);
4724b30f4fSZhihuan He clrsetbits_le32(&priv->phy->phy_reg0,
4824b30f4fSZhihuan He RESET_DIGITAL_CORE_MASK | RESET_ANALOG_LOGIC_MASK,
4924b30f4fSZhihuan He RESET_DIGITAL_CORE_ACT << RESET_DIGITAL_CORE_SHIFT |
5024b30f4fSZhihuan He RESET_ANALOG_LOGIC_ACT << RESET_ANALOG_LOGIC_SHIFT);
5124b30f4fSZhihuan He udelay(1);
5224b30f4fSZhihuan He clrsetbits_le32(&priv->phy->phy_reg0,
5324b30f4fSZhihuan He RESET_ANALOG_LOGIC_MASK,
5424b30f4fSZhihuan He RESET_ANALOG_LOGIC_DIS << RESET_ANALOG_LOGIC_SHIFT);
5524b30f4fSZhihuan He udelay(5);
5624b30f4fSZhihuan He clrsetbits_le32(&priv->phy->phy_reg0,
5724b30f4fSZhihuan He RESET_DIGITAL_CORE_MASK,
5824b30f4fSZhihuan He RESET_DIGITAL_CORE_DIS << RESET_DIGITAL_CORE_SHIFT);
5924b30f4fSZhihuan He udelay(1);
6024b30f4fSZhihuan He }
6124b30f4fSZhihuan He
phy_dll_bypass_set(struct dram_info * priv,unsigned int freq)6224b30f4fSZhihuan He static void phy_dll_bypass_set(struct dram_info *priv, unsigned int freq)
6324b30f4fSZhihuan He {
64786fea6fSWesley Yao clrsetbits_le32(&priv->phy->phy_reg13,
65786fea6fSWesley Yao CMD_DLL_BYPASS_MASK << CMD_DLL_BYPASS_SHIFT,
6624b30f4fSZhihuan He CMD_DLL_BYPASS << CMD_DLL_BYPASS_SHIFT);
6724b30f4fSZhihuan He
6824b30f4fSZhihuan He writel(CK_DLL_BYPASS_DISABLE << CK_DLL_BYPASS_SHIFT,
6924b30f4fSZhihuan He &priv->phy->phy_reg14);
7024b30f4fSZhihuan He
71786fea6fSWesley Yao clrsetbits_le32(&priv->phy->phy_reg26,
72786fea6fSWesley Yao LEFT_CHN_A_DQ_DLL_BYPASS_MASK << LEFT_CHN_A_DQ_DLL_SHIFT,
7324b30f4fSZhihuan He LEFT_CHN_A_DQ_DLL_BYPASS << LEFT_CHN_A_DQ_DLL_SHIFT);
74786fea6fSWesley Yao writel(LEFT_CHN_A_DQS_DLL_BYPASS_DIS << LEFT_CHN_A_DQS_DLL_SHIFT,
75786fea6fSWesley Yao &priv->phy->phy_reg27);
7624b30f4fSZhihuan He
77786fea6fSWesley Yao clrsetbits_le32(&priv->phy->phy_reg36,
78786fea6fSWesley Yao RIGHT_CHN_A_DQ_DLL_BYPASS_MASK << RIGHT_CHN_A_DQ_DLL_SHIFT,
79786fea6fSWesley Yao RIGHT_CHN_A_DQ_DLL_BYPASS << RIGHT_CHN_A_DQ_DLL_SHIFT);
8024b30f4fSZhihuan He writel(RIGHT_CHN_A_DQS_DLL_BYPASS_DIS <<
8124b30f4fSZhihuan He RIGHT_CHN_A_DQS_DLL_SHIFT, &priv->phy->phy_reg37);
8224b30f4fSZhihuan He
8324b30f4fSZhihuan He if (freq <= PHY_LOW_SPEED_MHZ) {
8424b30f4fSZhihuan He writel(RIGHT_CHN_A_TX_DQ_BYPASS_SET <<
8524b30f4fSZhihuan He RIGHT_CHN_A_TX_DQ_BYPASS_SHIFT |
8624b30f4fSZhihuan He LEFT_CHN_A_TX_DQ_BYPASS_SET <<
8724b30f4fSZhihuan He LEFT_CHN_A_TX_DQ_BYPASS_SHIFT |
8824b30f4fSZhihuan He CMD_CK_DLL_BYPASS_SET << CMD_CK_DLL_BYPASS_SHIFT,
8924b30f4fSZhihuan He &priv->phy->phy_regdll);
9024b30f4fSZhihuan He } else {
9124b30f4fSZhihuan He writel(RIGHT_CHN_A_TX_DQ_BYPASS_DIS <<
9224b30f4fSZhihuan He RIGHT_CHN_A_TX_DQ_BYPASS_SHIFT |
9324b30f4fSZhihuan He LEFT_CHN_A_TX_DQ_BYPASS_DIS <<
9424b30f4fSZhihuan He LEFT_CHN_A_TX_DQ_BYPASS_SHIFT |
9524b30f4fSZhihuan He CMD_CK_DLL_BYPASS_DIS << CMD_CK_DLL_BYPASS_SHIFT,
9624b30f4fSZhihuan He &priv->phy->phy_regdll);
9724b30f4fSZhihuan He }
9824b30f4fSZhihuan He
99b86c816cSZhihuan He ddr_phy_dqs_rx_dll_cfg(priv, freq);
10024b30f4fSZhihuan He }
10124b30f4fSZhihuan He
send_command(struct dram_info * priv,u32 rank,u32 cmd,u32 arg)10224b30f4fSZhihuan He static void send_command(struct dram_info *priv,
10324b30f4fSZhihuan He u32 rank, u32 cmd, u32 arg)
10424b30f4fSZhihuan He {
10524b30f4fSZhihuan He writel((START_CMD | (rank << RANK_SEL_SHIFT) | arg | cmd),
10624b30f4fSZhihuan He &priv->pctl->mcmd);
10724b30f4fSZhihuan He while (readl(&priv->pctl->mcmd) & START_CMD)
10824b30f4fSZhihuan He ;
10924b30f4fSZhihuan He }
11024b30f4fSZhihuan He
memory_init(struct dram_info * priv,struct sdram_params * params_priv)11124b30f4fSZhihuan He static void memory_init(struct dram_info *priv,
11224b30f4fSZhihuan He struct sdram_params *params_priv)
11324b30f4fSZhihuan He {
114b86c816cSZhihuan He u32 mr0;
115b86c816cSZhihuan He
116b86c816cSZhihuan He if (params_priv->ddr_config_t.ddr_type == DDR3 ||
117b86c816cSZhihuan He params_priv->ddr_config_t.ddr_type == DDR2) {
11824b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, DESELECT_CMD, 0);
11924b30f4fSZhihuan He udelay(1);
12024b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, PREA_CMD, 0);
12124b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, DESELECT_CMD, 0);
12224b30f4fSZhihuan He udelay(1);
12324b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
12424b30f4fSZhihuan He (MR2 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
12524b30f4fSZhihuan He (params_priv->ddr_timing_t.phy_timing.mr[2] &
12624b30f4fSZhihuan He CMD_ADDR_MASK) << CMD_ADDR_SHIFT);
12724b30f4fSZhihuan He
12824b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
12924b30f4fSZhihuan He (MR3 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
13024b30f4fSZhihuan He (params_priv->ddr_timing_t.phy_timing.mr[3] &
13124b30f4fSZhihuan He CMD_ADDR_MASK) << CMD_ADDR_SHIFT);
13224b30f4fSZhihuan He
13324b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
13424b30f4fSZhihuan He (MR1 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
13524b30f4fSZhihuan He (params_priv->ddr_timing_t.phy_timing.mr[1] &
13624b30f4fSZhihuan He CMD_ADDR_MASK) << CMD_ADDR_SHIFT);
13724b30f4fSZhihuan He
138b86c816cSZhihuan He mr0 = params_priv->ddr_timing_t.phy_timing.mr[0];
139b86c816cSZhihuan He if (params_priv->ddr_config_t.ddr_type == DDR3) {
14024b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
14124b30f4fSZhihuan He (MR0 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
142b86c816cSZhihuan He (((mr0 | DDR3_DLL_RESET) &
143b86c816cSZhihuan He CMD_ADDR_MASK) << CMD_ADDR_SHIFT));
14424b30f4fSZhihuan He
14524b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, ZQCL_CMD, 0);
146b86c816cSZhihuan He } else {
147b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
148b86c816cSZhihuan He (MR0 & BANK_ADDR_MASK) << BANK_ADDR_SHIFT |
149b86c816cSZhihuan He (((mr0 | DDR3_DLL_RESET) &
150b86c816cSZhihuan He CMD_ADDR_MASK) << CMD_ADDR_SHIFT));
151b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, PREA_CMD, 0);
152b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, REF_CMD, 0);
153b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, REF_CMD, 0);
154b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
155b86c816cSZhihuan He (MR0 & BANK_ADDR_MASK) <<
156b86c816cSZhihuan He BANK_ADDR_SHIFT |
157b86c816cSZhihuan He ((mr0 & CMD_ADDR_MASK) <<
158b86c816cSZhihuan He CMD_ADDR_SHIFT));
15924b30f4fSZhihuan He }
160b86c816cSZhihuan He } else {
161b86c816cSZhihuan He /* reset */
162b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
163b86c816cSZhihuan He (63 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
164b86c816cSZhihuan He (0 & LPDDR23_OP_MASK) <<
165b86c816cSZhihuan He LPDDR23_OP_SHIFT);
166b86c816cSZhihuan He /* tINIT5 */
167b86c816cSZhihuan He udelay(10);
168b86c816cSZhihuan He /* ZQ calibration Init */
169b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0, MRS_CMD,
170b86c816cSZhihuan He (10 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
171b86c816cSZhihuan He (0xFF & LPDDR23_OP_MASK) <<
172b86c816cSZhihuan He LPDDR23_OP_SHIFT);
173b86c816cSZhihuan He /* tZQINIT */
174b86c816cSZhihuan He udelay(1);
175b86c816cSZhihuan He send_command(priv, RANK_SEL_CS1, MRS_CMD,
176b86c816cSZhihuan He (10 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
177b86c816cSZhihuan He (0xFF & LPDDR23_OP_MASK) <<
178b86c816cSZhihuan He LPDDR23_OP_SHIFT);
179b86c816cSZhihuan He /* tZQINIT */
180b86c816cSZhihuan He udelay(1);
181b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
182b86c816cSZhihuan He (1 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
183b86c816cSZhihuan He (params_priv->ddr_timing_t.phy_timing.mr[1] &
184b86c816cSZhihuan He LPDDR23_OP_MASK) << LPDDR23_OP_SHIFT);
185b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
186b86c816cSZhihuan He (2 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
187b86c816cSZhihuan He (params_priv->ddr_timing_t.phy_timing.mr[2] &
188b86c816cSZhihuan He LPDDR23_OP_MASK) << LPDDR23_OP_SHIFT);
189b86c816cSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, MRS_CMD,
190b86c816cSZhihuan He (3 & LPDDR23_MA_MASK) << LPDDR23_MA_SHIFT |
191b86c816cSZhihuan He (params_priv->ddr_timing_t.phy_timing.mr[3] &
192b86c816cSZhihuan He LPDDR23_OP_MASK) << LPDDR23_OP_SHIFT);
19324b30f4fSZhihuan He }
19424b30f4fSZhihuan He }
19524b30f4fSZhihuan He
move_to_config_state(struct dram_info * priv)196b86c816cSZhihuan He void move_to_config_state(struct dram_info *priv)
19724b30f4fSZhihuan He {
19824b30f4fSZhihuan He unsigned int state;
19924b30f4fSZhihuan He
20024b30f4fSZhihuan He while (1) {
20124b30f4fSZhihuan He state = readl(&priv->pctl->stat) & PCTL_CTL_STAT_MASK;
20224b30f4fSZhihuan He switch (state) {
20324b30f4fSZhihuan He case LOW_POWER:
20424b30f4fSZhihuan He writel(WAKEUP_STATE, &priv->pctl->sctl);
20524b30f4fSZhihuan He while ((readl(&priv->pctl->stat) & PCTL_CTL_STAT_MASK)
20624b30f4fSZhihuan He != ACCESS)
20724b30f4fSZhihuan He ;
20824b30f4fSZhihuan He /*
20924b30f4fSZhihuan He * If at low power state, need wakeup first, and then
21024b30f4fSZhihuan He * enter the config, so fallthrough
21124b30f4fSZhihuan He */
21224b30f4fSZhihuan He case ACCESS:
21324b30f4fSZhihuan He case INIT_MEM:
21424b30f4fSZhihuan He writel(CFG_STATE, &priv->pctl->sctl);
21524b30f4fSZhihuan He while ((readl(&priv->pctl->stat) & PCTL_CTL_STAT_MASK)
21624b30f4fSZhihuan He != CONFIG)
21724b30f4fSZhihuan He ;
21824b30f4fSZhihuan He break;
21924b30f4fSZhihuan He case CONFIG:
22024b30f4fSZhihuan He return;
22124b30f4fSZhihuan He default:
22224b30f4fSZhihuan He break;
22324b30f4fSZhihuan He }
22424b30f4fSZhihuan He }
22524b30f4fSZhihuan He }
22624b30f4fSZhihuan He
move_to_access_state(struct dram_info * priv)227b86c816cSZhihuan He void move_to_access_state(struct dram_info *priv)
22824b30f4fSZhihuan He {
22924b30f4fSZhihuan He unsigned int state;
23024b30f4fSZhihuan He
23124b30f4fSZhihuan He while (1) {
23224b30f4fSZhihuan He state = readl(&priv->pctl->stat) & PCTL_CTL_STAT_MASK;
23324b30f4fSZhihuan He switch (state) {
23424b30f4fSZhihuan He case LOW_POWER:
23524b30f4fSZhihuan He writel(WAKEUP_STATE, &priv->pctl->sctl);
23624b30f4fSZhihuan He while ((readl(&priv->pctl->stat) &
23724b30f4fSZhihuan He PCTL_CTL_STAT_MASK) != ACCESS)
23824b30f4fSZhihuan He ;
23924b30f4fSZhihuan He break;
24024b30f4fSZhihuan He case INIT_MEM:
24124b30f4fSZhihuan He writel(CFG_STATE, &priv->pctl->sctl);
24224b30f4fSZhihuan He while ((readl(&priv->pctl->stat) &
24324b30f4fSZhihuan He PCTL_CTL_STAT_MASK) != CONFIG)
24424b30f4fSZhihuan He ;
24524b30f4fSZhihuan He /* fallthrough */
24624b30f4fSZhihuan He case CONFIG:
24724b30f4fSZhihuan He writel(GO_STATE, &priv->pctl->sctl);
24824b30f4fSZhihuan He while ((readl(&priv->pctl->stat) &
24924b30f4fSZhihuan He PCTL_CTL_STAT_MASK) != ACCESS)
25024b30f4fSZhihuan He ;
25124b30f4fSZhihuan He break;
25224b30f4fSZhihuan He case ACCESS:
25324b30f4fSZhihuan He return;
25424b30f4fSZhihuan He default:
25524b30f4fSZhihuan He break;
25624b30f4fSZhihuan He }
25724b30f4fSZhihuan He }
25824b30f4fSZhihuan He }
25924b30f4fSZhihuan He
pctl_cfg(struct dram_info * priv,struct sdram_params * params_priv)26024b30f4fSZhihuan He static void pctl_cfg(struct dram_info *priv,
26124b30f4fSZhihuan He struct sdram_params *params_priv)
26224b30f4fSZhihuan He {
26324b30f4fSZhihuan He u32 reg;
264b86c816cSZhihuan He u32 burstlen;
265b86c816cSZhihuan He u32 bl_mddr_lpddr2;
26624b30f4fSZhihuan He
26724b30f4fSZhihuan He /* DFI config */
26824b30f4fSZhihuan He writel(DFI_DATA_BYTE_DISABLE_EN << DFI_DATA_BYTE_DISABLE_EN_SHIFT |
26924b30f4fSZhihuan He DFI_INIT_START_EN << DFI_INIT_START_SHIFT,
27024b30f4fSZhihuan He &priv->pctl->dfistcfg0);
27124b30f4fSZhihuan He writel(DFI_DRAM_CLK_DISABLE_EN_DPD <<
27224b30f4fSZhihuan He DFI_DRAM_CLK_DISABLE_EN_DPD_SHIFT |
27324b30f4fSZhihuan He DFI_DRAM_CLK_DISABLE_EN << DFI_DRAM_CLK_DISABLE_EN_SHIFT,
27424b30f4fSZhihuan He &priv->pctl->dfistcfg1);
27524b30f4fSZhihuan He writel(PARITY_EN << PARITY_EN_SHIFT |
27624b30f4fSZhihuan He PARITY_INTR_EN << PARITY_INTR_EN_SHIFT, &priv->pctl->dfistcfg2);
27724b30f4fSZhihuan He
27824b30f4fSZhihuan He writel(TPHYUPD_TYPE0, &priv->pctl->dfitphyupdtype0);
27924b30f4fSZhihuan He writel(TPHY_RDLAT, &priv->pctl->dfitphyrdlat);
28024b30f4fSZhihuan He writel(TPHY_WRDATA, &priv->pctl->dfitphywrdata);
28124b30f4fSZhihuan He
28224b30f4fSZhihuan He writel(DFI_PHYUPD_DISABLE | DFI_CTRLUPD_DISABLE,
28324b30f4fSZhihuan He &priv->pctl->dfiupdcfg);
28424b30f4fSZhihuan He
28524b30f4fSZhihuan He copy_to_reg(&priv->pctl->togcnt1u,
286bc45a182SZhihuan He ¶ms_priv->ddr_timing_t.pctl_timing.togcnt1u,
28724b30f4fSZhihuan He sizeof(struct pctl_timing));
288b86c816cSZhihuan He /*
289b86c816cSZhihuan He * rv1108 phy is 1:2 mode, noc_timing.b.burstlen
290b86c816cSZhihuan He * have divide by scheuler clock, so need to * 4
291b86c816cSZhihuan He */
292b86c816cSZhihuan He burstlen = params_priv->ddr_timing_t.noc_timing.b.burstlen * 4;
29324b30f4fSZhihuan He
294b86c816cSZhihuan He if (params_priv->ddr_config_t.ddr_type == DDR3 ||
295b86c816cSZhihuan He params_priv->ddr_config_t.ddr_type == DDR2) {
29624b30f4fSZhihuan He writel((RANK0_ODT_WRITE_SEL << RANK0_ODT_WRITE_SEL_SHIFT |
29724b30f4fSZhihuan He RANK1_ODT_WRITE_SEL << RANK1_ODT_WRITE_SEL_SHIFT),
29824b30f4fSZhihuan He &priv->pctl->dfiodtcfg);
29924b30f4fSZhihuan He
30024b30f4fSZhihuan He writel(ODT_LEN_BL8_W << ODT_LEN_BL8_W_SHIFT,
30124b30f4fSZhihuan He &priv->pctl->dfiodtcfg1);
30224b30f4fSZhihuan He
303b86c816cSZhihuan He writel(params_priv->ddr_timing_t.pctl_timing.trsth,
304b86c816cSZhihuan He &priv->pctl->trsth);
305b86c816cSZhihuan He if (params_priv->ddr_config_t.ddr_type == DDR3)
306b86c816cSZhihuan He writel(MDDR_LPDDR23_CLOCK_STOP_IDLE_DIS | DDR3_EN |
307b86c816cSZhihuan He MEM_BL_8 | TFAW_CFG_5_TDDR |
308b86c816cSZhihuan He PD_EXIT_SLOW_EXIT_MODE | PD_TYPE_ACT_PD |
309b86c816cSZhihuan He PD_IDLE_DISABLE |
310b86c816cSZhihuan He params_priv->ddr_2t_en << TWO_T_SHIFT,
311b86c816cSZhihuan He &priv->pctl->mcfg);
312b86c816cSZhihuan He else if (burstlen == 8)
313b86c816cSZhihuan He writel(MDDR_LPDDR23_CLOCK_STOP_IDLE_DIS | DDR2_EN |
314b86c816cSZhihuan He MEM_BL_8 | TFAW_CFG_5_TDDR |
315b86c816cSZhihuan He PD_EXIT_SLOW_EXIT_MODE | PD_TYPE_ACT_PD |
316b86c816cSZhihuan He PD_IDLE_DISABLE |
317b86c816cSZhihuan He params_priv->ddr_2t_en << TWO_T_SHIFT,
318b86c816cSZhihuan He &priv->pctl->mcfg);
319b86c816cSZhihuan He else
320b86c816cSZhihuan He writel(MDDR_LPDDR23_CLOCK_STOP_IDLE_DIS | DDR2_EN |
321b86c816cSZhihuan He MEM_BL_4 | TFAW_CFG_5_TDDR |
322b86c816cSZhihuan He PD_EXIT_SLOW_EXIT_MODE | PD_TYPE_ACT_PD |
323b86c816cSZhihuan He PD_IDLE_DISABLE |
324b86c816cSZhihuan He params_priv->ddr_2t_en << TWO_T_SHIFT,
325b86c816cSZhihuan He &priv->pctl->mcfg);
326b86c816cSZhihuan He writel(DFI_LP_EN_SR << DFI_LP_EN_SR_SHIFT |
327b86c816cSZhihuan He DFI_LP_WAKEUP_SR_32_CYCLES << DFI_LP_WAKEUP_SR_SHIFT |
328b86c816cSZhihuan He DFI_TLP_RESP << DFI_TLP_RESP_SHIFT,
329b86c816cSZhihuan He &priv->pctl->dfilpcfg0);
330b86c816cSZhihuan He
33124b30f4fSZhihuan He reg = readl(&priv->pctl->tcl);
33224b30f4fSZhihuan He writel((reg - 1) / 2 - 1, &priv->pctl->dfitrddataen);
33324b30f4fSZhihuan He reg = readl(&priv->pctl->tcwl);
33424b30f4fSZhihuan He writel((reg - 1) / 2 - 1, &priv->pctl->dfitphywrlat);
335b86c816cSZhihuan He } else {
336b86c816cSZhihuan He if (burstlen == 4)
337b86c816cSZhihuan He bl_mddr_lpddr2 = MDDR_LPDDR2_BL_4;
338b86c816cSZhihuan He else
339b86c816cSZhihuan He bl_mddr_lpddr2 = MDDR_LPDDR2_BL_8;
340b86c816cSZhihuan He writel((RANK0_ODT_WRITE_DIS << RANK0_ODT_WRITE_SEL_SHIFT |
341b86c816cSZhihuan He RANK1_ODT_WRITE_DIS << RANK1_ODT_WRITE_SEL_SHIFT),
342b86c816cSZhihuan He &priv->pctl->dfiodtcfg);
34324b30f4fSZhihuan He
344b86c816cSZhihuan He writel(ODT_LEN_BL8_W_0 << ODT_LEN_BL8_W_SHIFT,
345b86c816cSZhihuan He &priv->pctl->dfiodtcfg1);
346b86c816cSZhihuan He
347b86c816cSZhihuan He writel(0, &priv->pctl->trsth);
348b86c816cSZhihuan He writel(MDDR_LPDDR23_CLOCK_STOP_IDLE_DIS | LPDDR2_EN |
349b86c816cSZhihuan He LPDDR2_S4 | bl_mddr_lpddr2 |
350b86c816cSZhihuan He TFAW_CFG_6_TDDR | PD_EXIT_FAST_EXIT_MODE |
35124b30f4fSZhihuan He PD_TYPE_ACT_PD | PD_IDLE_DISABLE, &priv->pctl->mcfg);
352b86c816cSZhihuan He writel(DFI_LP_EN_SR << DFI_LP_EN_SR_SHIFT |
353b86c816cSZhihuan He DFI_LP_WAKEUP_SR_32_CYCLES << DFI_LP_WAKEUP_SR_SHIFT |
354b86c816cSZhihuan He DFI_TLP_RESP << DFI_TLP_RESP_SHIFT |
355b86c816cSZhihuan He DFI_LP_WAKEUP_PD_32_CYCLES << DFI_LP_WAKEUP_PD_SHIFT |
356b86c816cSZhihuan He DFI_LP_EN_PD,
357b86c816cSZhihuan He &priv->pctl->dfilpcfg0);
35824b30f4fSZhihuan He
359b86c816cSZhihuan He reg = readl(&priv->pctl->tcl);
360b86c816cSZhihuan He writel(reg / 2 - 1, &priv->pctl->dfitrddataen);
361b86c816cSZhihuan He reg = readl(&priv->pctl->tcwl);
362b86c816cSZhihuan He writel(reg / 2 - 1, &priv->pctl->dfitphywrlat);
363b86c816cSZhihuan He }
364b86c816cSZhihuan He pctl_cfg_grf(priv, params_priv);
36524b30f4fSZhihuan He setbits_le32(&priv->pctl->scfg, HW_LOW_POWER_EN);
366b86c816cSZhihuan He
367b86c816cSZhihuan He /* only support x16 memory */
368b86c816cSZhihuan He clrsetbits_le32(&priv->pctl->ppcfg, PPMEM_EN_MASK, PPMEM_EN);
36924b30f4fSZhihuan He }
37024b30f4fSZhihuan He
phy_cfg(struct dram_info * priv,struct sdram_params * params_priv)37124b30f4fSZhihuan He static void phy_cfg(struct dram_info *priv,
37224b30f4fSZhihuan He struct sdram_params *params_priv)
37324b30f4fSZhihuan He {
374b86c816cSZhihuan He u32 burstlen;
37524b30f4fSZhihuan He
376b86c816cSZhihuan He burstlen = params_priv->ddr_timing_t.noc_timing.b.burstlen * 4;
377b86c816cSZhihuan He burstlen = (burstlen == 4) ? PHY_BL_4 : PHY_BL_8;
378b86c816cSZhihuan He ddr_msch_cfg(priv, params_priv);
379b86c816cSZhihuan He ddr_phy_skew_cfg(priv);
380b86c816cSZhihuan He switch (params_priv->ddr_config_t.ddr_type) {
381b86c816cSZhihuan He case DDR2:
382b86c816cSZhihuan He writel(MEMORY_SELECT_DDR2 | PHY_BL_8, &priv->phy->phy_reg1);
383b86c816cSZhihuan He break;
384b86c816cSZhihuan He case DDR3:
38524b30f4fSZhihuan He writel(MEMORY_SELECT_DDR3 | PHY_BL_8, &priv->phy->phy_reg1);
386b86c816cSZhihuan He break;
387b86c816cSZhihuan He case LPDDR2:
388b86c816cSZhihuan He default:
389b86c816cSZhihuan He writel(MEMORY_SELECT_LPDDR2 | burstlen, &priv->phy->phy_reg1);
390b86c816cSZhihuan He break;
391b86c816cSZhihuan He }
39224b30f4fSZhihuan He
39324b30f4fSZhihuan He writel(params_priv->ddr_timing_t.phy_timing.cl_al,
39424b30f4fSZhihuan He &priv->phy->phy_regb);
39524b30f4fSZhihuan He writel(params_priv->ddr_timing_t.pctl_timing.tcwl,
39624b30f4fSZhihuan He &priv->phy->phy_regc);
39724b30f4fSZhihuan He
398b86c816cSZhihuan He set_ds_odt(priv, params_priv);
399b86c816cSZhihuan He
400b86c816cSZhihuan He /* only support x16 memory */
401b86c816cSZhihuan He clrsetbits_le32(&priv->phy->phy_reg0, DQ_16BIT_EN_MASK,
402b86c816cSZhihuan He DQ_16BIT_EN);
40324b30f4fSZhihuan He }
40424b30f4fSZhihuan He
dram_cfg_rbc(struct dram_info * priv,struct sdram_params * params_priv)40524b30f4fSZhihuan He static void dram_cfg_rbc(struct dram_info *priv,
40624b30f4fSZhihuan He struct sdram_params *params_priv)
40724b30f4fSZhihuan He {
40824b30f4fSZhihuan He move_to_config_state(priv);
409b86c816cSZhihuan He ddr_msch_cfg_rbc(params_priv, priv);
41024b30f4fSZhihuan He move_to_access_state(priv);
41124b30f4fSZhihuan He }
41224b30f4fSZhihuan He
data_training(struct dram_info * priv)41324b30f4fSZhihuan He static void data_training(struct dram_info *priv)
41424b30f4fSZhihuan He {
41524b30f4fSZhihuan He u32 value;
41624b30f4fSZhihuan He u32 tmp = 0;
417b86c816cSZhihuan He u32 tmp1 = 0;
418b86c816cSZhihuan He u32 timeout = 1000;
41924b30f4fSZhihuan He
42024b30f4fSZhihuan He /* disable auto refresh */
42124b30f4fSZhihuan He value = readl(&priv->pctl->trefi);
42224b30f4fSZhihuan He writel(UPD_REF, &priv->pctl->trefi);
42324b30f4fSZhihuan He
424b86c816cSZhihuan He tmp1 = readl(&priv->phy->phy_reg2);
425b86c816cSZhihuan He
426b86c816cSZhihuan He writel(DQS_GATE_TRAINING_SEL_CS0 | DQS_GATE_TRAINING_DIS | tmp1,
42724b30f4fSZhihuan He &priv->phy->phy_reg2);
428b86c816cSZhihuan He writel(DQS_GATE_TRAINING_SEL_CS0 | DQS_GATE_TRAINING_ACT | tmp1,
42924b30f4fSZhihuan He &priv->phy->phy_reg2);
43024b30f4fSZhihuan He
431b86c816cSZhihuan He /* delay until data training done */
43224b30f4fSZhihuan He while (tmp != (CHN_A_HIGH_8BIT_TRAINING_DONE |
43324b30f4fSZhihuan He CHN_A_LOW_8BIT_TRAINING_DONE)) {
43424b30f4fSZhihuan He udelay(1);
43524b30f4fSZhihuan He tmp = (readl(&priv->phy->phy_regff) & CHN_A_TRAINING_DONE_MASK);
436b86c816cSZhihuan He timeout--;
437b86c816cSZhihuan He if (!timeout)
438b86c816cSZhihuan He break;
43924b30f4fSZhihuan He }
44024b30f4fSZhihuan He
441b86c816cSZhihuan He writel(DQS_GATE_TRAINING_SEL_CS0 | DQS_GATE_TRAINING_DIS | tmp1,
44224b30f4fSZhihuan He &priv->phy->phy_reg2);
44324b30f4fSZhihuan He
44424b30f4fSZhihuan He send_command(priv, RANK_SEL_CS0_CS1, PREA_CMD, 0);
44524b30f4fSZhihuan He
44624b30f4fSZhihuan He writel(value | UPD_REF, &priv->pctl->trefi);
44724b30f4fSZhihuan He }
44824b30f4fSZhihuan He
sdram_detect(struct dram_info * priv,struct sdram_params * params_priv)449b86c816cSZhihuan He static int sdram_detect(struct dram_info *priv,
45024b30f4fSZhihuan He struct sdram_params *params_priv)
45124b30f4fSZhihuan He {
452b86c816cSZhihuan He u32 row, col, row_max, col_max, bank_max;
453b86c816cSZhihuan He u32 bw = 1;
454b86c816cSZhihuan He phys_addr_t test_addr;
455b86c816cSZhihuan He struct ddr_schedule ddr_sch;
45624b30f4fSZhihuan He
457b86c816cSZhihuan He /* if col detect wrong,row needs initial */
458b86c816cSZhihuan He row = 0;
45924b30f4fSZhihuan He
46024b30f4fSZhihuan He /* detect col */
461b86c816cSZhihuan He move_to_config_state(priv);
462b86c816cSZhihuan He ddr_msch_get_max_col(priv, &ddr_sch);
463b86c816cSZhihuan He col_max = ddr_sch.col;
464b86c816cSZhihuan He bank_max = ddr_sch.bank;
465b86c816cSZhihuan He move_to_access_state(priv);
466b86c816cSZhihuan He
46724b30f4fSZhihuan He for (col = col_max; col >= 10; col--) {
468b86c816cSZhihuan He writel(0, CONFIG_SYS_SDRAM_BASE);
469b86c816cSZhihuan He test_addr = (phys_addr_t)(CONFIG_SYS_SDRAM_BASE +
470b86c816cSZhihuan He (1ul << (col + bw - 1ul)));
47124b30f4fSZhihuan He writel(PATTERN, test_addr);
47224b30f4fSZhihuan He if ((readl(test_addr) == PATTERN) &&
473b86c816cSZhihuan He (readl(CONFIG_SYS_SDRAM_BASE) == 0))
47424b30f4fSZhihuan He break;
47524b30f4fSZhihuan He }
476b86c816cSZhihuan He if (col <= 9)
47724b30f4fSZhihuan He goto cap_err;
478b86c816cSZhihuan He params_priv->ddr_config_t.col = col;
47924b30f4fSZhihuan He
480b86c816cSZhihuan He if (params_priv->ddr_config_t.ddr_type == DDR3) {
481b86c816cSZhihuan He params_priv->ddr_config_t.bank = 3;
482b86c816cSZhihuan He } else {
483b86c816cSZhihuan He writel(0, CONFIG_SYS_SDRAM_BASE);
484b86c816cSZhihuan He test_addr = (phys_addr_t)(CONFIG_SYS_SDRAM_BASE +
485b86c816cSZhihuan He (1ul << (bank_max + col_max +
486b86c816cSZhihuan He bw - 1ul)));
48724b30f4fSZhihuan He writel(PATTERN, test_addr);
48824b30f4fSZhihuan He if ((readl(test_addr) == PATTERN) &&
489b86c816cSZhihuan He (readl(CONFIG_SYS_SDRAM_BASE) == 0))
490b86c816cSZhihuan He params_priv->ddr_config_t.bank = 3;
491b86c816cSZhihuan He else
492b86c816cSZhihuan He params_priv->ddr_config_t.bank = 2;
493b86c816cSZhihuan He }
494b86c816cSZhihuan He
495b86c816cSZhihuan He /* detect row */
496b86c816cSZhihuan He move_to_config_state(priv);
497b86c816cSZhihuan He ddr_msch_get_max_row(priv, &ddr_sch);
498b86c816cSZhihuan He move_to_access_state(priv);
499b86c816cSZhihuan He col_max = ddr_sch.col;
500b86c816cSZhihuan He row_max = ddr_sch.row;
501b86c816cSZhihuan He
502b86c816cSZhihuan He for (row = row_max; row >= 12; row--) {
503b86c816cSZhihuan He writel(0, CONFIG_SYS_SDRAM_BASE);
504b86c816cSZhihuan He test_addr = (phys_addr_t)(CONFIG_SYS_SDRAM_BASE +
505b86c816cSZhihuan He (1ul << (row + bank_max +
506b86c816cSZhihuan He col_max + bw - 1ul)));
507b86c816cSZhihuan He
508b86c816cSZhihuan He writel(PATTERN, test_addr);
509b86c816cSZhihuan He if ((readl(test_addr) == PATTERN) &&
510b86c816cSZhihuan He (readl(CONFIG_SYS_SDRAM_BASE) == 0))
51124b30f4fSZhihuan He break;
51224b30f4fSZhihuan He }
51324b30f4fSZhihuan He if (row <= 11)
51424b30f4fSZhihuan He goto cap_err;
515b86c816cSZhihuan He params_priv->ddr_config_t.cs0_row = row;
51624b30f4fSZhihuan He return 0;
51724b30f4fSZhihuan He cap_err:
518b86c816cSZhihuan He return -EAGAIN;
51924b30f4fSZhihuan He }
52024b30f4fSZhihuan He
521b86c816cSZhihuan He #define DDR_VERSION 0x2
522b86c816cSZhihuan He
sdram_all_config(struct dram_info * priv,struct sdram_params * params_priv)52324b30f4fSZhihuan He static void sdram_all_config(struct dram_info *priv,
52424b30f4fSZhihuan He struct sdram_params *params_priv)
52524b30f4fSZhihuan He {
526b86c816cSZhihuan He u32 version = DDR_VERSION;
52724b30f4fSZhihuan He u32 os_reg = 0;
528b86c816cSZhihuan He u32 row_12 = 0;
529b86c816cSZhihuan He u32 ddr_info = 0;
530b86c816cSZhihuan He /* rk3308,rv1108 only support 1 channel, x16 ddr bus, x16 memory */
531b86c816cSZhihuan He u32 chn_cnt = 0;
532b86c816cSZhihuan He u32 rank = 1;
533b86c816cSZhihuan He u32 bw = 1;
534b86c816cSZhihuan He u32 dbw = 1;
535b86c816cSZhihuan He size_t size = 0;
536b86c816cSZhihuan He struct ddr_param ddr_param;
53724b30f4fSZhihuan He
538b86c816cSZhihuan He /* os_reg2 */
539b86c816cSZhihuan He os_reg = (params_priv->ddr_config_t.ddr_type & SYS_REG_DDRTYPE_MASK) <<
540b86c816cSZhihuan He SYS_REG_DDRTYPE_SHIFT |
541b86c816cSZhihuan He (chn_cnt & SYS_REG_NUM_CH_MASK) <<
542b86c816cSZhihuan He SYS_REG_NUM_CH_SHIFT |
543b86c816cSZhihuan He ((rank - 1) & SYS_REG_RANK_MASK) <<
544b86c816cSZhihuan He SYS_REG_RANK_SHIFT(0) |
545b86c816cSZhihuan He ((params_priv->ddr_config_t.col - 9) & SYS_REG_COL_MASK) <<
546b86c816cSZhihuan He SYS_REG_COL_SHIFT(0) |
547b86c816cSZhihuan He ((params_priv->ddr_config_t.bank == 3 ? 0 : 1) &
548b86c816cSZhihuan He SYS_REG_BK_MASK) << SYS_REG_BK_SHIFT(0) |
549b86c816cSZhihuan He ((params_priv->ddr_config_t.cs0_row - 13) &
550b86c816cSZhihuan He SYS_REG_CS0_ROW_MASK) << SYS_REG_CS0_ROW_SHIFT(0) |
551b86c816cSZhihuan He (bw & SYS_REG_BW_MASK) <<
552b86c816cSZhihuan He SYS_REG_BW_SHIFT(0) |
553b86c816cSZhihuan He (dbw & SYS_REG_DBW_MASK) <<
554b86c816cSZhihuan He SYS_REG_DBW_SHIFT(0);
55524b30f4fSZhihuan He
55624b30f4fSZhihuan He writel(os_reg, &priv->grf->os_reg2);
557b86c816cSZhihuan He
558b86c816cSZhihuan He /* os_reg3 */
559b86c816cSZhihuan He if (params_priv->ddr_config_t.cs0_row == 12)
560b86c816cSZhihuan He row_12 = 1;
561b86c816cSZhihuan He os_reg = (version & SYS_REG1_VERSION_MASK) <<
562b86c816cSZhihuan He SYS_REG1_VERSION_SHIFT | (row_12 &
563b86c816cSZhihuan He SYS_REG1_EXTEND_CS0_ROW_MASK) <<
564b86c816cSZhihuan He SYS_REG1_EXTEND_CS0_ROW_SHIFT(0);
565b86c816cSZhihuan He writel(os_reg, &priv->grf->os_reg3);
566b86c816cSZhihuan He
567b86c816cSZhihuan He printascii("In\n");
568b86c816cSZhihuan He printdec(params_priv->ddr_timing_t.freq);
569b86c816cSZhihuan He printascii("MHz\n");
570b86c816cSZhihuan He switch (params_priv->ddr_config_t.ddr_type & SYS_REG_DDRTYPE_MASK) {
571b86c816cSZhihuan He case 2:
572b86c816cSZhihuan He printascii("DDR2\n");
573b86c816cSZhihuan He break;
574b86c816cSZhihuan He case 5:
575b86c816cSZhihuan He printascii("LPDDR2\n");
576b86c816cSZhihuan He break;
577b86c816cSZhihuan He case 3:
578b86c816cSZhihuan He default:
579b86c816cSZhihuan He printascii("DDR3\n");
580b86c816cSZhihuan He break;
581b86c816cSZhihuan He }
582b86c816cSZhihuan He printascii(" Col=");
583b86c816cSZhihuan He printdec(params_priv->ddr_config_t.col);
584b86c816cSZhihuan He printascii(" Bank=");
585b86c816cSZhihuan He printdec(params_priv->ddr_config_t.bank);
586b86c816cSZhihuan He printascii(" Row=");
587b86c816cSZhihuan He printdec(params_priv->ddr_config_t.cs0_row);
588b86c816cSZhihuan He
589b86c816cSZhihuan He size = 1llu << (bw +
590b86c816cSZhihuan He params_priv->ddr_config_t.col +
591b86c816cSZhihuan He params_priv->ddr_config_t.cs0_row +
592b86c816cSZhihuan He params_priv->ddr_config_t.bank);
593b86c816cSZhihuan He ddr_info = size >> 20;
594b86c816cSZhihuan He printascii(" Size=");
595b86c816cSZhihuan He printdec(ddr_info);
596b86c816cSZhihuan He printascii("MB\n");
597b86c816cSZhihuan He printascii("msch:");
598b86c816cSZhihuan He ddr_info = readl(&priv->service_msch->ddrconf);
599b86c816cSZhihuan He printdec(ddr_info);
600b86c816cSZhihuan He printascii("\n");
601b86c816cSZhihuan He
602b86c816cSZhihuan He priv->info.base = CONFIG_SYS_SDRAM_BASE;
603b86c816cSZhihuan He priv->info.size = size;
604b86c816cSZhihuan He ddr_param.count = 1;
605b86c816cSZhihuan He ddr_param.para[0] = priv->info.base;
606b86c816cSZhihuan He ddr_param.para[1] = priv->info.size;
607b86c816cSZhihuan He rockchip_setup_ddr_param(&ddr_param);
60824b30f4fSZhihuan He }
60924b30f4fSZhihuan He
rv1108_sdram_init(struct dram_info * sdram_priv,struct sdram_params * params_priv)61024b30f4fSZhihuan He int rv1108_sdram_init(struct dram_info *sdram_priv,
61124b30f4fSZhihuan He struct sdram_params *params_priv)
61224b30f4fSZhihuan He {
61324b30f4fSZhihuan He /* pmu enable ddr io retention */
61424b30f4fSZhihuan He enable_ddr_io_ret(sdram_priv);
61524b30f4fSZhihuan He rkdclk_init(sdram_priv, params_priv);
61624b30f4fSZhihuan He phy_pctrl_reset(sdram_priv);
61724b30f4fSZhihuan He phy_dll_bypass_set(sdram_priv, params_priv->ddr_timing_t.freq);
61824b30f4fSZhihuan He pctl_cfg(sdram_priv, params_priv);
61924b30f4fSZhihuan He phy_cfg(sdram_priv, params_priv);
62024b30f4fSZhihuan He writel(POWER_UP_START, &sdram_priv->pctl->powctl);
62124b30f4fSZhihuan He while (!(readl(&sdram_priv->pctl->powstat) & POWER_UP_DONE))
62224b30f4fSZhihuan He ;
62324b30f4fSZhihuan He
62424b30f4fSZhihuan He memory_init(sdram_priv, params_priv);
625b86c816cSZhihuan He re_training:
62624b30f4fSZhihuan He move_to_config_state(sdram_priv);
62724b30f4fSZhihuan He data_training(sdram_priv);
62824b30f4fSZhihuan He move_to_access_state(sdram_priv);
62924b30f4fSZhihuan He if (sdram_detect(sdram_priv, params_priv)) {
63024b30f4fSZhihuan He while (1)
63124b30f4fSZhihuan He ;
63224b30f4fSZhihuan He }
633b86c816cSZhihuan He if (check_rd_gate(sdram_priv))
634b86c816cSZhihuan He goto re_training;
635b86c816cSZhihuan He
636b86c816cSZhihuan He /* workaround data training not in middle */
637b86c816cSZhihuan He modify_data_training(sdram_priv, params_priv);
638b86c816cSZhihuan He
63924b30f4fSZhihuan He dram_cfg_rbc(sdram_priv, params_priv);
64024b30f4fSZhihuan He sdram_all_config(sdram_priv, params_priv);
641b86c816cSZhihuan He enable_low_power(sdram_priv, params_priv);
64224b30f4fSZhihuan He
64324b30f4fSZhihuan He return 0;
64424b30f4fSZhihuan He }
645*19d63b30SZhihuan He
646*19d63b30SZhihuan He #endif /* CONFIG_TPL_BUILD */
647