1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * DDR3 mem setup file for board based on EXYNOS5
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2012 Samsung Electronics
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <config.h>
11*4882a593Smuzhiyun #include <asm/io.h>
12*4882a593Smuzhiyun #include <asm/arch/clock.h>
13*4882a593Smuzhiyun #include <asm/arch/cpu.h>
14*4882a593Smuzhiyun #include <asm/arch/dmc.h>
15*4882a593Smuzhiyun #include <asm/arch/power.h>
16*4882a593Smuzhiyun #include "common_setup.h"
17*4882a593Smuzhiyun #include "exynos5_setup.h"
18*4882a593Smuzhiyun #include "clock_init.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define TIMEOUT_US 10000
21*4882a593Smuzhiyun #define NUM_BYTE_LANES 4
22*4882a593Smuzhiyun #define DEFAULT_DQS 8
23*4882a593Smuzhiyun #define DEFAULT_DQS_X4 ((DEFAULT_DQS << 24) || (DEFAULT_DQS << 16) \
24*4882a593Smuzhiyun || (DEFAULT_DQS << 8) || (DEFAULT_DQS << 0))
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #ifdef CONFIG_EXYNOS5250
reset_phy_ctrl(void)27*4882a593Smuzhiyun static void reset_phy_ctrl(void)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun struct exynos5_clock *clk =
30*4882a593Smuzhiyun (struct exynos5_clock *)samsung_get_base_clock();
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun writel(DDR3PHY_CTRL_PHY_RESET_OFF, &clk->lpddr3phy_ctrl);
33*4882a593Smuzhiyun writel(DDR3PHY_CTRL_PHY_RESET, &clk->lpddr3phy_ctrl);
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun
ddr3_mem_ctrl_init(struct mem_timings * mem,int reset)36*4882a593Smuzhiyun int ddr3_mem_ctrl_init(struct mem_timings *mem, int reset)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun unsigned int val;
39*4882a593Smuzhiyun struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl;
40*4882a593Smuzhiyun struct exynos5_dmc *dmc;
41*4882a593Smuzhiyun int i;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun phy0_ctrl = (struct exynos5_phy_control *)samsung_get_base_dmc_phy();
44*4882a593Smuzhiyun phy1_ctrl = (struct exynos5_phy_control *)(samsung_get_base_dmc_phy()
45*4882a593Smuzhiyun + DMC_OFFSET);
46*4882a593Smuzhiyun dmc = (struct exynos5_dmc *)samsung_get_base_dmc_ctrl();
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun if (reset)
49*4882a593Smuzhiyun reset_phy_ctrl();
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* Set Impedance Output Driver */
52*4882a593Smuzhiyun val = (mem->impedance << CA_CK_DRVR_DS_OFFSET) |
53*4882a593Smuzhiyun (mem->impedance << CA_CKE_DRVR_DS_OFFSET) |
54*4882a593Smuzhiyun (mem->impedance << CA_CS_DRVR_DS_OFFSET) |
55*4882a593Smuzhiyun (mem->impedance << CA_ADR_DRVR_DS_OFFSET);
56*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con39);
57*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con39);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* Set Read Latency and Burst Length for PHY0 and PHY1 */
60*4882a593Smuzhiyun val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) |
61*4882a593Smuzhiyun (mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT);
62*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con42);
63*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con42);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* ZQ Calibration */
66*4882a593Smuzhiyun if (dmc_config_zq(mem, &phy0_ctrl->phy_con16, &phy1_ctrl->phy_con16,
67*4882a593Smuzhiyun &phy0_ctrl->phy_con17, &phy1_ctrl->phy_con17))
68*4882a593Smuzhiyun return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* DQ Signal */
71*4882a593Smuzhiyun writel(mem->phy0_pulld_dqs, &phy0_ctrl->phy_con14);
72*4882a593Smuzhiyun writel(mem->phy1_pulld_dqs, &phy1_ctrl->phy_con14);
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
75*4882a593Smuzhiyun | (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT),
76*4882a593Smuzhiyun &dmc->concontrol);
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* DQS Signal */
81*4882a593Smuzhiyun writel(mem->phy0_dqs, &phy0_ctrl->phy_con4);
82*4882a593Smuzhiyun writel(mem->phy1_dqs, &phy1_ctrl->phy_con4);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun writel(mem->phy0_dq, &phy0_ctrl->phy_con6);
85*4882a593Smuzhiyun writel(mem->phy1_dq, &phy1_ctrl->phy_con6);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun writel(mem->phy0_tFS, &phy0_ctrl->phy_con10);
88*4882a593Smuzhiyun writel(mem->phy1_tFS, &phy1_ctrl->phy_con10);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun val = (mem->ctrl_start_point << PHY_CON12_CTRL_START_POINT_SHIFT) |
91*4882a593Smuzhiyun (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
92*4882a593Smuzhiyun (mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
93*4882a593Smuzhiyun (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
94*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con12);
95*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con12);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /* Start DLL locking */
98*4882a593Smuzhiyun writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
99*4882a593Smuzhiyun &phy0_ctrl->phy_con12);
100*4882a593Smuzhiyun writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
101*4882a593Smuzhiyun &phy1_ctrl->phy_con12);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
106*4882a593Smuzhiyun &dmc->concontrol);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* Memory Channel Inteleaving Size */
109*4882a593Smuzhiyun writel(mem->iv_size, &dmc->ivcontrol);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun writel(mem->memconfig, &dmc->memconfig0);
112*4882a593Smuzhiyun writel(mem->memconfig, &dmc->memconfig1);
113*4882a593Smuzhiyun writel(mem->membaseconfig0, &dmc->membaseconfig0);
114*4882a593Smuzhiyun writel(mem->membaseconfig1, &dmc->membaseconfig1);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /* Precharge Configuration */
117*4882a593Smuzhiyun writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
118*4882a593Smuzhiyun &dmc->prechconfig);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* Power Down mode Configuration */
121*4882a593Smuzhiyun writel(mem->dpwrdn_cyc << PWRDNCONFIG_DPWRDN_CYC_SHIFT |
122*4882a593Smuzhiyun mem->dsref_cyc << PWRDNCONFIG_DSREF_CYC_SHIFT,
123*4882a593Smuzhiyun &dmc->pwrdnconfig);
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* TimingRow, TimingData, TimingPower and Timingaref
126*4882a593Smuzhiyun * values as per Memory AC parameters
127*4882a593Smuzhiyun */
128*4882a593Smuzhiyun writel(mem->timing_ref, &dmc->timingref);
129*4882a593Smuzhiyun writel(mem->timing_row, &dmc->timingrow);
130*4882a593Smuzhiyun writel(mem->timing_data, &dmc->timingdata);
131*4882a593Smuzhiyun writel(mem->timing_power, &dmc->timingpower);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* Send PALL command */
134*4882a593Smuzhiyun dmc_config_prech(mem, &dmc->directcmd);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* Send NOP, MRS and ZQINIT commands */
137*4882a593Smuzhiyun dmc_config_mrs(mem, &dmc->directcmd);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (mem->gate_leveling_enable) {
140*4882a593Smuzhiyun val = PHY_CON0_RESET_VAL;
141*4882a593Smuzhiyun val |= P0_CMD_EN;
142*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con0);
143*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con0);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun val = PHY_CON2_RESET_VAL;
146*4882a593Smuzhiyun val |= INIT_DESKEW_EN;
147*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con2);
148*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con2);
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun val = PHY_CON0_RESET_VAL;
151*4882a593Smuzhiyun val |= P0_CMD_EN;
152*4882a593Smuzhiyun val |= BYTE_RDLVL_EN;
153*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con0);
154*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con0);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun val = (mem->ctrl_start_point <<
157*4882a593Smuzhiyun PHY_CON12_CTRL_START_POINT_SHIFT) |
158*4882a593Smuzhiyun (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
159*4882a593Smuzhiyun (mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
160*4882a593Smuzhiyun (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
161*4882a593Smuzhiyun (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
162*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con12);
163*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con12);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun val = PHY_CON2_RESET_VAL;
166*4882a593Smuzhiyun val |= INIT_DESKEW_EN;
167*4882a593Smuzhiyun val |= RDLVL_GATE_EN;
168*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con2);
169*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con2);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun val = PHY_CON0_RESET_VAL;
172*4882a593Smuzhiyun val |= P0_CMD_EN;
173*4882a593Smuzhiyun val |= BYTE_RDLVL_EN;
174*4882a593Smuzhiyun val |= CTRL_SHGATE;
175*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con0);
176*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con0);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun val = PHY_CON1_RESET_VAL;
179*4882a593Smuzhiyun val &= ~(CTRL_GATEDURADJ_MASK);
180*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con1);
181*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con1);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config);
184*4882a593Smuzhiyun i = TIMEOUT_US;
185*4882a593Smuzhiyun while ((readl(&dmc->phystatus) &
186*4882a593Smuzhiyun (RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) !=
187*4882a593Smuzhiyun (RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) {
188*4882a593Smuzhiyun /*
189*4882a593Smuzhiyun * TODO(waihong): Comment on how long this take to
190*4882a593Smuzhiyun * timeout
191*4882a593Smuzhiyun */
192*4882a593Smuzhiyun sdelay(100);
193*4882a593Smuzhiyun i--;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun if (!i)
196*4882a593Smuzhiyun return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
197*4882a593Smuzhiyun writel(CTRL_RDLVL_GATE_DISABLE, &dmc->rdlvl_config);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun writel(0, &phy0_ctrl->phy_con14);
200*4882a593Smuzhiyun writel(0, &phy1_ctrl->phy_con14);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun val = (mem->ctrl_start_point <<
203*4882a593Smuzhiyun PHY_CON12_CTRL_START_POINT_SHIFT) |
204*4882a593Smuzhiyun (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
205*4882a593Smuzhiyun (mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
206*4882a593Smuzhiyun (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
207*4882a593Smuzhiyun (mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
208*4882a593Smuzhiyun (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
209*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con12);
210*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con12);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* Send PALL command */
216*4882a593Smuzhiyun dmc_config_prech(mem, &dmc->directcmd);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun writel(mem->memcontrol, &dmc->memcontrol);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /* Set DMC Concontrol and enable auto-refresh counter */
221*4882a593Smuzhiyun writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
222*4882a593Smuzhiyun | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT), &dmc->concontrol);
223*4882a593Smuzhiyun return 0;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun #endif
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun #ifdef CONFIG_EXYNOS5420
228*4882a593Smuzhiyun /**
229*4882a593Smuzhiyun * RAM address to use in the test.
230*4882a593Smuzhiyun *
231*4882a593Smuzhiyun * We'll use 4 words at this address and 4 at this address + 0x80 (Ares
232*4882a593Smuzhiyun * interleaves channels every 128 bytes). This will allow us to evaluate all of
233*4882a593Smuzhiyun * the chips in a 1 chip per channel (2GB) system and half the chips in a 2
234*4882a593Smuzhiyun * chip per channel (4GB) system. We can't test the 2nd chip since we need to
235*4882a593Smuzhiyun * do tests before the 2nd chip is enabled. Looking at the 2nd chip isn't
236*4882a593Smuzhiyun * critical because the 1st and 2nd chip have very similar timings (they'd
237*4882a593Smuzhiyun * better have similar timings, since there's only a single adjustment that is
238*4882a593Smuzhiyun * shared by both chips).
239*4882a593Smuzhiyun */
240*4882a593Smuzhiyun const unsigned int test_addr = CONFIG_SYS_SDRAM_BASE;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* Test pattern with which RAM will be tested */
243*4882a593Smuzhiyun static const unsigned int test_pattern[] = {
244*4882a593Smuzhiyun 0x5a5a5a5a,
245*4882a593Smuzhiyun 0xa5a5a5a5,
246*4882a593Smuzhiyun 0xf0f0f0f0,
247*4882a593Smuzhiyun 0x0f0f0f0f,
248*4882a593Smuzhiyun };
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /**
251*4882a593Smuzhiyun * This function is a test vector for sw read leveling,
252*4882a593Smuzhiyun * it compares the read data with the written data.
253*4882a593Smuzhiyun *
254*4882a593Smuzhiyun * @param ch DMC channel number
255*4882a593Smuzhiyun * @param byte_lane which DQS byte offset,
256*4882a593Smuzhiyun * possible values are 0,1,2,3
257*4882a593Smuzhiyun * @return TRUE if memory was good, FALSE if not.
258*4882a593Smuzhiyun */
dmc_valid_window_test_vector(int ch,int byte_lane)259*4882a593Smuzhiyun static bool dmc_valid_window_test_vector(int ch, int byte_lane)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun unsigned int read_data;
262*4882a593Smuzhiyun unsigned int mask;
263*4882a593Smuzhiyun int i;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun mask = 0xFF << (8 * byte_lane);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(test_pattern); i++) {
268*4882a593Smuzhiyun read_data = readl(test_addr + i * 4 + ch * 0x80);
269*4882a593Smuzhiyun if ((read_data & mask) != (test_pattern[i] & mask))
270*4882a593Smuzhiyun return false;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun return true;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /**
277*4882a593Smuzhiyun * This function returns current read offset value.
278*4882a593Smuzhiyun *
279*4882a593Smuzhiyun * @param phy_ctrl pointer to the current phy controller
280*4882a593Smuzhiyun */
dmc_get_read_offset_value(struct exynos5420_phy_control * phy_ctrl)281*4882a593Smuzhiyun static unsigned int dmc_get_read_offset_value(struct exynos5420_phy_control
282*4882a593Smuzhiyun *phy_ctrl)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun return readl(&phy_ctrl->phy_con4);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun /**
288*4882a593Smuzhiyun * This function performs resync, so that slave DLL is updated.
289*4882a593Smuzhiyun *
290*4882a593Smuzhiyun * @param phy_ctrl pointer to the current phy controller
291*4882a593Smuzhiyun */
ddr_phy_set_do_resync(struct exynos5420_phy_control * phy_ctrl)292*4882a593Smuzhiyun static void ddr_phy_set_do_resync(struct exynos5420_phy_control *phy_ctrl)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun setbits_le32(&phy_ctrl->phy_con10, PHY_CON10_CTRL_OFFSETR3);
295*4882a593Smuzhiyun clrbits_le32(&phy_ctrl->phy_con10, PHY_CON10_CTRL_OFFSETR3);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /**
299*4882a593Smuzhiyun * This function sets read offset value register with 'offset'.
300*4882a593Smuzhiyun *
301*4882a593Smuzhiyun * ...we also call call ddr_phy_set_do_resync().
302*4882a593Smuzhiyun *
303*4882a593Smuzhiyun * @param phy_ctrl pointer to the current phy controller
304*4882a593Smuzhiyun * @param offset offset to read DQS
305*4882a593Smuzhiyun */
dmc_set_read_offset_value(struct exynos5420_phy_control * phy_ctrl,unsigned int offset)306*4882a593Smuzhiyun static void dmc_set_read_offset_value(struct exynos5420_phy_control *phy_ctrl,
307*4882a593Smuzhiyun unsigned int offset)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun writel(offset, &phy_ctrl->phy_con4);
310*4882a593Smuzhiyun ddr_phy_set_do_resync(phy_ctrl);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /**
314*4882a593Smuzhiyun * Convert a 2s complement byte to a byte with a sign bit.
315*4882a593Smuzhiyun *
316*4882a593Smuzhiyun * NOTE: you shouldn't use normal math on the number returned by this function.
317*4882a593Smuzhiyun * As an example, -10 = 0xf6. After this function -10 = 0x8a. If you wanted
318*4882a593Smuzhiyun * to do math and get the average of 10 and -10 (should be 0):
319*4882a593Smuzhiyun * 0x8a + 0xa = 0x94 (-108)
320*4882a593Smuzhiyun * 0x94 / 2 = 0xca (-54)
321*4882a593Smuzhiyun * ...and 0xca = sign bit plus 0x4a, or -74
322*4882a593Smuzhiyun *
323*4882a593Smuzhiyun * Also note that you lose the ability to represent -128 since there are two
324*4882a593Smuzhiyun * representations of 0.
325*4882a593Smuzhiyun *
326*4882a593Smuzhiyun * @param b The byte to convert in two's complement.
327*4882a593Smuzhiyun * @return The 7-bit value + sign bit.
328*4882a593Smuzhiyun */
329*4882a593Smuzhiyun
make_signed_byte(signed char b)330*4882a593Smuzhiyun unsigned char make_signed_byte(signed char b)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun if (b < 0)
333*4882a593Smuzhiyun return 0x80 | -b;
334*4882a593Smuzhiyun else
335*4882a593Smuzhiyun return b;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /**
339*4882a593Smuzhiyun * Test various shifts starting at 'start' and going to 'end'.
340*4882a593Smuzhiyun *
341*4882a593Smuzhiyun * For each byte lane, we'll walk through shift starting at 'start' and going
342*4882a593Smuzhiyun * to 'end' (inclusive). When we are finally able to read the test pattern
343*4882a593Smuzhiyun * we'll store the value in the results array.
344*4882a593Smuzhiyun *
345*4882a593Smuzhiyun * @param phy_ctrl pointer to the current phy controller
346*4882a593Smuzhiyun * @param ch channel number
347*4882a593Smuzhiyun * @param start the start shift. -127 to 127
348*4882a593Smuzhiyun * @param end the end shift. -127 to 127
349*4882a593Smuzhiyun * @param results we'll store results for each byte lane.
350*4882a593Smuzhiyun */
351*4882a593Smuzhiyun
test_shifts(struct exynos5420_phy_control * phy_ctrl,int ch,int start,int end,int results[NUM_BYTE_LANES])352*4882a593Smuzhiyun void test_shifts(struct exynos5420_phy_control *phy_ctrl, int ch,
353*4882a593Smuzhiyun int start, int end, int results[NUM_BYTE_LANES])
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun int incr = (start < end) ? 1 : -1;
356*4882a593Smuzhiyun int byte_lane;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun for (byte_lane = 0; byte_lane < NUM_BYTE_LANES; byte_lane++) {
359*4882a593Smuzhiyun int shift;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun dmc_set_read_offset_value(phy_ctrl, DEFAULT_DQS_X4);
362*4882a593Smuzhiyun results[byte_lane] = DEFAULT_DQS;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun for (shift = start; shift != (end + incr); shift += incr) {
365*4882a593Smuzhiyun unsigned int byte_offsetr;
366*4882a593Smuzhiyun unsigned int offsetr;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun byte_offsetr = make_signed_byte(shift);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun offsetr = dmc_get_read_offset_value(phy_ctrl);
371*4882a593Smuzhiyun offsetr &= ~(0xFF << (8 * byte_lane));
372*4882a593Smuzhiyun offsetr |= (byte_offsetr << (8 * byte_lane));
373*4882a593Smuzhiyun dmc_set_read_offset_value(phy_ctrl, offsetr);
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun if (dmc_valid_window_test_vector(ch, byte_lane)) {
376*4882a593Smuzhiyun results[byte_lane] = shift;
377*4882a593Smuzhiyun break;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /**
384*4882a593Smuzhiyun * This function performs SW read leveling to compensate DQ-DQS skew at
385*4882a593Smuzhiyun * receiver it first finds the optimal read offset value on each DQS
386*4882a593Smuzhiyun * then applies the value to PHY.
387*4882a593Smuzhiyun *
388*4882a593Smuzhiyun * Read offset value has its min margin and max margin. If read offset
389*4882a593Smuzhiyun * value exceeds its min or max margin, read data will have corruption.
390*4882a593Smuzhiyun * To avoid this we are doing sw read leveling.
391*4882a593Smuzhiyun *
392*4882a593Smuzhiyun * SW read leveling is:
393*4882a593Smuzhiyun * 1> Finding offset value's left_limit and right_limit
394*4882a593Smuzhiyun * 2> and calculate its center value
395*4882a593Smuzhiyun * 3> finally programs that center value to PHY
396*4882a593Smuzhiyun * 4> then PHY gets its optimal offset value.
397*4882a593Smuzhiyun *
398*4882a593Smuzhiyun * @param phy_ctrl pointer to the current phy controller
399*4882a593Smuzhiyun * @param ch channel number
400*4882a593Smuzhiyun * @param coarse_lock_val The coarse lock value read from PHY_CON13.
401*4882a593Smuzhiyun * (0 - 0x7f)
402*4882a593Smuzhiyun */
software_find_read_offset(struct exynos5420_phy_control * phy_ctrl,int ch,unsigned int coarse_lock_val)403*4882a593Smuzhiyun static void software_find_read_offset(struct exynos5420_phy_control *phy_ctrl,
404*4882a593Smuzhiyun int ch, unsigned int coarse_lock_val)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun unsigned int offsetr_cent;
407*4882a593Smuzhiyun int byte_lane;
408*4882a593Smuzhiyun int left_limit;
409*4882a593Smuzhiyun int right_limit;
410*4882a593Smuzhiyun int left[NUM_BYTE_LANES];
411*4882a593Smuzhiyun int right[NUM_BYTE_LANES];
412*4882a593Smuzhiyun int i;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun /* Fill the memory with test patterns */
415*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(test_pattern); i++)
416*4882a593Smuzhiyun writel(test_pattern[i], test_addr + i * 4 + ch * 0x80);
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun /* Figure out the limits we'll test with; keep -127 < limit < 127 */
419*4882a593Smuzhiyun left_limit = DEFAULT_DQS - coarse_lock_val;
420*4882a593Smuzhiyun right_limit = DEFAULT_DQS + coarse_lock_val;
421*4882a593Smuzhiyun if (right_limit > 127)
422*4882a593Smuzhiyun right_limit = 127;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /* Fill in the location where reads were OK from left and right */
425*4882a593Smuzhiyun test_shifts(phy_ctrl, ch, left_limit, right_limit, left);
426*4882a593Smuzhiyun test_shifts(phy_ctrl, ch, right_limit, left_limit, right);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /* Make a final value by taking the center between the left and right */
429*4882a593Smuzhiyun offsetr_cent = 0;
430*4882a593Smuzhiyun for (byte_lane = 0; byte_lane < NUM_BYTE_LANES; byte_lane++) {
431*4882a593Smuzhiyun int temp_center;
432*4882a593Smuzhiyun unsigned int vmwc;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun temp_center = (left[byte_lane] + right[byte_lane]) / 2;
435*4882a593Smuzhiyun vmwc = make_signed_byte(temp_center);
436*4882a593Smuzhiyun offsetr_cent |= vmwc << (8 * byte_lane);
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun dmc_set_read_offset_value(phy_ctrl, offsetr_cent);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
ddr3_mem_ctrl_init(struct mem_timings * mem,int reset)441*4882a593Smuzhiyun int ddr3_mem_ctrl_init(struct mem_timings *mem, int reset)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun struct exynos5420_clock *clk =
444*4882a593Smuzhiyun (struct exynos5420_clock *)samsung_get_base_clock();
445*4882a593Smuzhiyun struct exynos5420_power *power =
446*4882a593Smuzhiyun (struct exynos5420_power *)samsung_get_base_power();
447*4882a593Smuzhiyun struct exynos5420_phy_control *phy0_ctrl, *phy1_ctrl;
448*4882a593Smuzhiyun struct exynos5420_dmc *drex0, *drex1;
449*4882a593Smuzhiyun struct exynos5420_tzasc *tzasc0, *tzasc1;
450*4882a593Smuzhiyun struct exynos5_power *pmu;
451*4882a593Smuzhiyun uint32_t val, n_lock_r, n_lock_w_phy0, n_lock_w_phy1;
452*4882a593Smuzhiyun uint32_t lock0_info, lock1_info;
453*4882a593Smuzhiyun int chip;
454*4882a593Smuzhiyun int i;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun phy0_ctrl = (struct exynos5420_phy_control *)samsung_get_base_dmc_phy();
457*4882a593Smuzhiyun phy1_ctrl = (struct exynos5420_phy_control *)(samsung_get_base_dmc_phy()
458*4882a593Smuzhiyun + DMC_OFFSET);
459*4882a593Smuzhiyun drex0 = (struct exynos5420_dmc *)samsung_get_base_dmc_ctrl();
460*4882a593Smuzhiyun drex1 = (struct exynos5420_dmc *)(samsung_get_base_dmc_ctrl()
461*4882a593Smuzhiyun + DMC_OFFSET);
462*4882a593Smuzhiyun tzasc0 = (struct exynos5420_tzasc *)samsung_get_base_dmc_tzasc();
463*4882a593Smuzhiyun tzasc1 = (struct exynos5420_tzasc *)(samsung_get_base_dmc_tzasc()
464*4882a593Smuzhiyun + DMC_OFFSET);
465*4882a593Smuzhiyun pmu = (struct exynos5_power *)EXYNOS5420_POWER_BASE;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun if (CONFIG_NR_DRAM_BANKS > 4) {
468*4882a593Smuzhiyun /* Need both controllers. */
469*4882a593Smuzhiyun mem->memcontrol |= DMC_MEMCONTROL_NUM_CHIP_2;
470*4882a593Smuzhiyun mem->chips_per_channel = 2;
471*4882a593Smuzhiyun mem->chips_to_configure = 2;
472*4882a593Smuzhiyun } else {
473*4882a593Smuzhiyun /* 2GB requires a single controller */
474*4882a593Smuzhiyun mem->memcontrol |= DMC_MEMCONTROL_NUM_CHIP_1;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun /* Enable PAUSE for DREX */
478*4882a593Smuzhiyun setbits_le32(&clk->pause, ENABLE_BIT);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun /* Enable BYPASS mode */
481*4882a593Smuzhiyun setbits_le32(&clk->bpll_con1, BYPASS_EN);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun writel(MUX_BPLL_SEL_FOUTBPLL, &clk->src_cdrex);
484*4882a593Smuzhiyun do {
485*4882a593Smuzhiyun val = readl(&clk->mux_stat_cdrex);
486*4882a593Smuzhiyun val &= BPLL_SEL_MASK;
487*4882a593Smuzhiyun } while (val != FOUTBPLL);
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun clrbits_le32(&clk->bpll_con1, BYPASS_EN);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun /* Specify the DDR memory type as DDR3 */
492*4882a593Smuzhiyun val = readl(&phy0_ctrl->phy_con0);
493*4882a593Smuzhiyun val &= ~(PHY_CON0_CTRL_DDR_MODE_MASK << PHY_CON0_CTRL_DDR_MODE_SHIFT);
494*4882a593Smuzhiyun val |= (DDR_MODE_DDR3 << PHY_CON0_CTRL_DDR_MODE_SHIFT);
495*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con0);
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun val = readl(&phy1_ctrl->phy_con0);
498*4882a593Smuzhiyun val &= ~(PHY_CON0_CTRL_DDR_MODE_MASK << PHY_CON0_CTRL_DDR_MODE_SHIFT);
499*4882a593Smuzhiyun val |= (DDR_MODE_DDR3 << PHY_CON0_CTRL_DDR_MODE_SHIFT);
500*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con0);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* Set Read Latency and Burst Length for PHY0 and PHY1 */
503*4882a593Smuzhiyun val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) |
504*4882a593Smuzhiyun (mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT);
505*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con42);
506*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con42);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun val = readl(&phy0_ctrl->phy_con26);
509*4882a593Smuzhiyun val &= ~(T_WRDATA_EN_MASK << T_WRDATA_EN_OFFSET);
510*4882a593Smuzhiyun val |= (T_WRDATA_EN_DDR3 << T_WRDATA_EN_OFFSET);
511*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con26);
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun val = readl(&phy1_ctrl->phy_con26);
514*4882a593Smuzhiyun val &= ~(T_WRDATA_EN_MASK << T_WRDATA_EN_OFFSET);
515*4882a593Smuzhiyun val |= (T_WRDATA_EN_DDR3 << T_WRDATA_EN_OFFSET);
516*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con26);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /*
519*4882a593Smuzhiyun * Set Driver strength for CK, CKE, CS & CA to 0x7
520*4882a593Smuzhiyun * Set Driver strength for Data Slice 0~3 to 0x7
521*4882a593Smuzhiyun */
522*4882a593Smuzhiyun val = (0x7 << CA_CK_DRVR_DS_OFFSET) | (0x7 << CA_CKE_DRVR_DS_OFFSET) |
523*4882a593Smuzhiyun (0x7 << CA_CS_DRVR_DS_OFFSET) | (0x7 << CA_ADR_DRVR_DS_OFFSET);
524*4882a593Smuzhiyun val |= (0x7 << DA_3_DS_OFFSET) | (0x7 << DA_2_DS_OFFSET) |
525*4882a593Smuzhiyun (0x7 << DA_1_DS_OFFSET) | (0x7 << DA_0_DS_OFFSET);
526*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con39);
527*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con39);
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /* ZQ Calibration */
530*4882a593Smuzhiyun if (dmc_config_zq(mem, &phy0_ctrl->phy_con16, &phy1_ctrl->phy_con16,
531*4882a593Smuzhiyun &phy0_ctrl->phy_con17, &phy1_ctrl->phy_con17))
532*4882a593Smuzhiyun return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun clrbits_le32(&phy0_ctrl->phy_con16, ZQ_CLK_DIV_EN);
535*4882a593Smuzhiyun clrbits_le32(&phy1_ctrl->phy_con16, ZQ_CLK_DIV_EN);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun /* DQ Signal */
538*4882a593Smuzhiyun val = readl(&phy0_ctrl->phy_con14);
539*4882a593Smuzhiyun val |= mem->phy0_pulld_dqs;
540*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con14);
541*4882a593Smuzhiyun val = readl(&phy1_ctrl->phy_con14);
542*4882a593Smuzhiyun val |= mem->phy1_pulld_dqs;
543*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con14);
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun val = MEM_TERM_EN | PHY_TERM_EN;
546*4882a593Smuzhiyun writel(val, &drex0->phycontrol0);
547*4882a593Smuzhiyun writel(val, &drex1->phycontrol0);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun writel(mem->concontrol |
550*4882a593Smuzhiyun (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT) |
551*4882a593Smuzhiyun (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
552*4882a593Smuzhiyun &drex0->concontrol);
553*4882a593Smuzhiyun writel(mem->concontrol |
554*4882a593Smuzhiyun (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT) |
555*4882a593Smuzhiyun (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
556*4882a593Smuzhiyun &drex1->concontrol);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun do {
559*4882a593Smuzhiyun val = readl(&drex0->phystatus);
560*4882a593Smuzhiyun } while ((val & DFI_INIT_COMPLETE) != DFI_INIT_COMPLETE);
561*4882a593Smuzhiyun do {
562*4882a593Smuzhiyun val = readl(&drex1->phystatus);
563*4882a593Smuzhiyun } while ((val & DFI_INIT_COMPLETE) != DFI_INIT_COMPLETE);
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun clrbits_le32(&drex0->concontrol, DFI_INIT_START);
566*4882a593Smuzhiyun clrbits_le32(&drex1->concontrol, DFI_INIT_START);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun update_reset_dll(&drex0->phycontrol0, DDR_MODE_DDR3);
569*4882a593Smuzhiyun update_reset_dll(&drex1->phycontrol0, DDR_MODE_DDR3);
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun /*
572*4882a593Smuzhiyun * Set Base Address:
573*4882a593Smuzhiyun * 0x2000_0000 ~ 0x5FFF_FFFF
574*4882a593Smuzhiyun * 0x6000_0000 ~ 0x9FFF_FFFF
575*4882a593Smuzhiyun */
576*4882a593Smuzhiyun /* MEMBASECONFIG0 */
577*4882a593Smuzhiyun val = DMC_MEMBASECONFIGX_CHIP_BASE(DMC_CHIP_BASE_0) |
578*4882a593Smuzhiyun DMC_MEMBASECONFIGX_CHIP_MASK(DMC_CHIP_MASK);
579*4882a593Smuzhiyun writel(val, &tzasc0->membaseconfig0);
580*4882a593Smuzhiyun writel(val, &tzasc1->membaseconfig0);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /* MEMBASECONFIG1 */
583*4882a593Smuzhiyun val = DMC_MEMBASECONFIGX_CHIP_BASE(DMC_CHIP_BASE_1) |
584*4882a593Smuzhiyun DMC_MEMBASECONFIGX_CHIP_MASK(DMC_CHIP_MASK);
585*4882a593Smuzhiyun writel(val, &tzasc0->membaseconfig1);
586*4882a593Smuzhiyun writel(val, &tzasc1->membaseconfig1);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun /*
589*4882a593Smuzhiyun * Memory Channel Inteleaving Size
590*4882a593Smuzhiyun * Ares Channel interleaving = 128 bytes
591*4882a593Smuzhiyun */
592*4882a593Smuzhiyun /* MEMCONFIG0/1 */
593*4882a593Smuzhiyun writel(mem->memconfig, &tzasc0->memconfig0);
594*4882a593Smuzhiyun writel(mem->memconfig, &tzasc1->memconfig0);
595*4882a593Smuzhiyun writel(mem->memconfig, &tzasc0->memconfig1);
596*4882a593Smuzhiyun writel(mem->memconfig, &tzasc1->memconfig1);
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun /* Precharge Configuration */
599*4882a593Smuzhiyun writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
600*4882a593Smuzhiyun &drex0->prechconfig0);
601*4882a593Smuzhiyun writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
602*4882a593Smuzhiyun &drex1->prechconfig0);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun /*
605*4882a593Smuzhiyun * TimingRow, TimingData, TimingPower and Timingaref
606*4882a593Smuzhiyun * values as per Memory AC parameters
607*4882a593Smuzhiyun */
608*4882a593Smuzhiyun writel(mem->timing_ref, &drex0->timingref);
609*4882a593Smuzhiyun writel(mem->timing_ref, &drex1->timingref);
610*4882a593Smuzhiyun writel(mem->timing_row, &drex0->timingrow0);
611*4882a593Smuzhiyun writel(mem->timing_row, &drex1->timingrow0);
612*4882a593Smuzhiyun writel(mem->timing_data, &drex0->timingdata0);
613*4882a593Smuzhiyun writel(mem->timing_data, &drex1->timingdata0);
614*4882a593Smuzhiyun writel(mem->timing_power, &drex0->timingpower0);
615*4882a593Smuzhiyun writel(mem->timing_power, &drex1->timingpower0);
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun if (reset) {
618*4882a593Smuzhiyun /*
619*4882a593Smuzhiyun * Send NOP, MRS and ZQINIT commands
620*4882a593Smuzhiyun * Sending MRS command will reset the DRAM. We should not be
621*4882a593Smuzhiyun * resetting the DRAM after resume, this will lead to memory
622*4882a593Smuzhiyun * corruption as DRAM content is lost after DRAM reset
623*4882a593Smuzhiyun */
624*4882a593Smuzhiyun dmc_config_mrs(mem, &drex0->directcmd);
625*4882a593Smuzhiyun dmc_config_mrs(mem, &drex1->directcmd);
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun /*
629*4882a593Smuzhiyun * Get PHY_CON13 from both phys. Gate CLKM around reading since
630*4882a593Smuzhiyun * PHY_CON13 is glitchy when CLKM is running. We're paranoid and
631*4882a593Smuzhiyun * wait until we get a "fine lock", though a coarse lock is probably
632*4882a593Smuzhiyun * OK (we only use the coarse numbers below). We try to gate the
633*4882a593Smuzhiyun * clock for as short a time as possible in case SDRAM is somehow
634*4882a593Smuzhiyun * sensitive. sdelay(10) in the loop is arbitrary to make sure
635*4882a593Smuzhiyun * there is some time for PHY_CON13 to get updated. In practice
636*4882a593Smuzhiyun * no delay appears to be needed.
637*4882a593Smuzhiyun */
638*4882a593Smuzhiyun val = readl(&clk->gate_bus_cdrex);
639*4882a593Smuzhiyun while (true) {
640*4882a593Smuzhiyun writel(val & ~0x1, &clk->gate_bus_cdrex);
641*4882a593Smuzhiyun lock0_info = readl(&phy0_ctrl->phy_con13);
642*4882a593Smuzhiyun writel(val, &clk->gate_bus_cdrex);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun if ((lock0_info & CTRL_FINE_LOCKED) == CTRL_FINE_LOCKED)
645*4882a593Smuzhiyun break;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun sdelay(10);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun while (true) {
650*4882a593Smuzhiyun writel(val & ~0x2, &clk->gate_bus_cdrex);
651*4882a593Smuzhiyun lock1_info = readl(&phy1_ctrl->phy_con13);
652*4882a593Smuzhiyun writel(val, &clk->gate_bus_cdrex);
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun if ((lock1_info & CTRL_FINE_LOCKED) == CTRL_FINE_LOCKED)
655*4882a593Smuzhiyun break;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun sdelay(10);
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun if (!reset) {
661*4882a593Smuzhiyun /*
662*4882a593Smuzhiyun * During Suspend-Resume & S/W-Reset, as soon as PMU releases
663*4882a593Smuzhiyun * pad retention, CKE goes high. This causes memory contents
664*4882a593Smuzhiyun * not to be retained during DRAM initialization. Therfore,
665*4882a593Smuzhiyun * there is a new control register(0x100431e8[28]) which lets us
666*4882a593Smuzhiyun * release pad retention and retain the memory content until the
667*4882a593Smuzhiyun * initialization is complete.
668*4882a593Smuzhiyun */
669*4882a593Smuzhiyun writel(PAD_RETENTION_DRAM_COREBLK_VAL,
670*4882a593Smuzhiyun &power->pad_retention_dram_coreblk_option);
671*4882a593Smuzhiyun do {
672*4882a593Smuzhiyun val = readl(&power->pad_retention_dram_status);
673*4882a593Smuzhiyun } while (val != 0x1);
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun /*
676*4882a593Smuzhiyun * CKE PAD retention disables DRAM self-refresh mode.
677*4882a593Smuzhiyun * Send auto refresh command for DRAM refresh.
678*4882a593Smuzhiyun */
679*4882a593Smuzhiyun for (i = 0; i < 128; i++) {
680*4882a593Smuzhiyun for (chip = 0; chip < mem->chips_to_configure; chip++) {
681*4882a593Smuzhiyun writel(DIRECT_CMD_REFA |
682*4882a593Smuzhiyun (chip << DIRECT_CMD_CHIP_SHIFT),
683*4882a593Smuzhiyun &drex0->directcmd);
684*4882a593Smuzhiyun writel(DIRECT_CMD_REFA |
685*4882a593Smuzhiyun (chip << DIRECT_CMD_CHIP_SHIFT),
686*4882a593Smuzhiyun &drex1->directcmd);
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun if (mem->gate_leveling_enable) {
692*4882a593Smuzhiyun writel(PHY_CON0_RESET_VAL, &phy0_ctrl->phy_con0);
693*4882a593Smuzhiyun writel(PHY_CON0_RESET_VAL, &phy1_ctrl->phy_con0);
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun setbits_le32(&phy0_ctrl->phy_con0, P0_CMD_EN);
696*4882a593Smuzhiyun setbits_le32(&phy1_ctrl->phy_con0, P0_CMD_EN);
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun val = PHY_CON2_RESET_VAL;
699*4882a593Smuzhiyun val |= INIT_DESKEW_EN;
700*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con2);
701*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con2);
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun val = readl(&phy0_ctrl->phy_con1);
704*4882a593Smuzhiyun val |= (RDLVL_PASS_ADJ_VAL << RDLVL_PASS_ADJ_OFFSET);
705*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con1);
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun val = readl(&phy1_ctrl->phy_con1);
708*4882a593Smuzhiyun val |= (RDLVL_PASS_ADJ_VAL << RDLVL_PASS_ADJ_OFFSET);
709*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con1);
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun n_lock_w_phy0 = (lock0_info & CTRL_LOCK_COARSE_MASK) >> 2;
712*4882a593Smuzhiyun n_lock_r = readl(&phy0_ctrl->phy_con12);
713*4882a593Smuzhiyun n_lock_r &= ~CTRL_DLL_ON;
714*4882a593Smuzhiyun n_lock_r |= n_lock_w_phy0;
715*4882a593Smuzhiyun writel(n_lock_r, &phy0_ctrl->phy_con12);
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun n_lock_w_phy1 = (lock1_info & CTRL_LOCK_COARSE_MASK) >> 2;
718*4882a593Smuzhiyun n_lock_r = readl(&phy1_ctrl->phy_con12);
719*4882a593Smuzhiyun n_lock_r &= ~CTRL_DLL_ON;
720*4882a593Smuzhiyun n_lock_r |= n_lock_w_phy1;
721*4882a593Smuzhiyun writel(n_lock_r, &phy1_ctrl->phy_con12);
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun val = (0x3 << DIRECT_CMD_BANK_SHIFT) | 0x4;
724*4882a593Smuzhiyun for (chip = 0; chip < mem->chips_to_configure; chip++) {
725*4882a593Smuzhiyun writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
726*4882a593Smuzhiyun &drex0->directcmd);
727*4882a593Smuzhiyun writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
728*4882a593Smuzhiyun &drex1->directcmd);
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun setbits_le32(&phy0_ctrl->phy_con2, RDLVL_GATE_EN);
732*4882a593Smuzhiyun setbits_le32(&phy1_ctrl->phy_con2, RDLVL_GATE_EN);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun setbits_le32(&phy0_ctrl->phy_con0, CTRL_SHGATE);
735*4882a593Smuzhiyun setbits_le32(&phy1_ctrl->phy_con0, CTRL_SHGATE);
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun val = readl(&phy0_ctrl->phy_con1);
738*4882a593Smuzhiyun val &= ~(CTRL_GATEDURADJ_MASK);
739*4882a593Smuzhiyun writel(val, &phy0_ctrl->phy_con1);
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun val = readl(&phy1_ctrl->phy_con1);
742*4882a593Smuzhiyun val &= ~(CTRL_GATEDURADJ_MASK);
743*4882a593Smuzhiyun writel(val, &phy1_ctrl->phy_con1);
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun writel(CTRL_RDLVL_GATE_ENABLE, &drex0->rdlvl_config);
746*4882a593Smuzhiyun i = TIMEOUT_US;
747*4882a593Smuzhiyun while (((readl(&drex0->phystatus) & RDLVL_COMPLETE_CHO) !=
748*4882a593Smuzhiyun RDLVL_COMPLETE_CHO) && (i > 0)) {
749*4882a593Smuzhiyun /*
750*4882a593Smuzhiyun * TODO(waihong): Comment on how long this take to
751*4882a593Smuzhiyun * timeout
752*4882a593Smuzhiyun */
753*4882a593Smuzhiyun sdelay(100);
754*4882a593Smuzhiyun i--;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun if (!i)
757*4882a593Smuzhiyun return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
758*4882a593Smuzhiyun writel(CTRL_RDLVL_GATE_DISABLE, &drex0->rdlvl_config);
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun writel(CTRL_RDLVL_GATE_ENABLE, &drex1->rdlvl_config);
761*4882a593Smuzhiyun i = TIMEOUT_US;
762*4882a593Smuzhiyun while (((readl(&drex1->phystatus) & RDLVL_COMPLETE_CHO) !=
763*4882a593Smuzhiyun RDLVL_COMPLETE_CHO) && (i > 0)) {
764*4882a593Smuzhiyun /*
765*4882a593Smuzhiyun * TODO(waihong): Comment on how long this take to
766*4882a593Smuzhiyun * timeout
767*4882a593Smuzhiyun */
768*4882a593Smuzhiyun sdelay(100);
769*4882a593Smuzhiyun i--;
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun if (!i)
772*4882a593Smuzhiyun return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
773*4882a593Smuzhiyun writel(CTRL_RDLVL_GATE_DISABLE, &drex1->rdlvl_config);
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun writel(0, &phy0_ctrl->phy_con14);
776*4882a593Smuzhiyun writel(0, &phy1_ctrl->phy_con14);
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun val = (0x3 << DIRECT_CMD_BANK_SHIFT);
779*4882a593Smuzhiyun for (chip = 0; chip < mem->chips_to_configure; chip++) {
780*4882a593Smuzhiyun writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
781*4882a593Smuzhiyun &drex0->directcmd);
782*4882a593Smuzhiyun writel(val | (chip << DIRECT_CMD_CHIP_SHIFT),
783*4882a593Smuzhiyun &drex1->directcmd);
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun /* Common Settings for Leveling */
787*4882a593Smuzhiyun val = PHY_CON12_RESET_VAL;
788*4882a593Smuzhiyun writel((val + n_lock_w_phy0), &phy0_ctrl->phy_con12);
789*4882a593Smuzhiyun writel((val + n_lock_w_phy1), &phy1_ctrl->phy_con12);
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun setbits_le32(&phy0_ctrl->phy_con2, DLL_DESKEW_EN);
792*4882a593Smuzhiyun setbits_le32(&phy1_ctrl->phy_con2, DLL_DESKEW_EN);
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun /*
796*4882a593Smuzhiyun * Do software read leveling
797*4882a593Smuzhiyun *
798*4882a593Smuzhiyun * Do this before we turn on auto refresh since the auto refresh can
799*4882a593Smuzhiyun * be in conflict with the resync operation that's part of setting
800*4882a593Smuzhiyun * read leveling.
801*4882a593Smuzhiyun */
802*4882a593Smuzhiyun if (!reset) {
803*4882a593Smuzhiyun /* restore calibrated value after resume */
804*4882a593Smuzhiyun dmc_set_read_offset_value(phy0_ctrl, readl(&pmu->pmu_spare1));
805*4882a593Smuzhiyun dmc_set_read_offset_value(phy1_ctrl, readl(&pmu->pmu_spare2));
806*4882a593Smuzhiyun } else {
807*4882a593Smuzhiyun software_find_read_offset(phy0_ctrl, 0,
808*4882a593Smuzhiyun CTRL_LOCK_COARSE(lock0_info));
809*4882a593Smuzhiyun software_find_read_offset(phy1_ctrl, 1,
810*4882a593Smuzhiyun CTRL_LOCK_COARSE(lock1_info));
811*4882a593Smuzhiyun /* save calibrated value to restore after resume */
812*4882a593Smuzhiyun writel(dmc_get_read_offset_value(phy0_ctrl), &pmu->pmu_spare1);
813*4882a593Smuzhiyun writel(dmc_get_read_offset_value(phy1_ctrl), &pmu->pmu_spare2);
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun /* Send PALL command */
817*4882a593Smuzhiyun dmc_config_prech(mem, &drex0->directcmd);
818*4882a593Smuzhiyun dmc_config_prech(mem, &drex1->directcmd);
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun writel(mem->memcontrol, &drex0->memcontrol);
821*4882a593Smuzhiyun writel(mem->memcontrol, &drex1->memcontrol);
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun /*
824*4882a593Smuzhiyun * Set DMC Concontrol: Enable auto-refresh counter, provide
825*4882a593Smuzhiyun * read data fetch cycles and enable DREX auto set powerdown
826*4882a593Smuzhiyun * for input buffer of I/O in none read memory state.
827*4882a593Smuzhiyun */
828*4882a593Smuzhiyun writel(mem->concontrol | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT) |
829*4882a593Smuzhiyun (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)|
830*4882a593Smuzhiyun DMC_CONCONTROL_IO_PD_CON(0x2),
831*4882a593Smuzhiyun &drex0->concontrol);
832*4882a593Smuzhiyun writel(mem->concontrol | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT) |
833*4882a593Smuzhiyun (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)|
834*4882a593Smuzhiyun DMC_CONCONTROL_IO_PD_CON(0x2),
835*4882a593Smuzhiyun &drex1->concontrol);
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun /*
838*4882a593Smuzhiyun * Enable Clock Gating Control for DMC
839*4882a593Smuzhiyun * this saves around 25 mw dmc power as compared to the power
840*4882a593Smuzhiyun * consumption without these bits enabled
841*4882a593Smuzhiyun */
842*4882a593Smuzhiyun setbits_le32(&drex0->cgcontrol, DMC_INTERNAL_CG);
843*4882a593Smuzhiyun setbits_le32(&drex1->cgcontrol, DMC_INTERNAL_CG);
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun /*
846*4882a593Smuzhiyun * As per Exynos5800 UM ver 0.00 section 17.13.2.1
847*4882a593Smuzhiyun * CONCONTROL register bit 3 [update_mode], Exynos5800 does not
848*4882a593Smuzhiyun * support the PHY initiated update. And it is recommended to set
849*4882a593Smuzhiyun * this field to 1'b1 during initialization
850*4882a593Smuzhiyun *
851*4882a593Smuzhiyun * When we apply PHY-initiated mode, DLL lock value is determined
852*4882a593Smuzhiyun * once at DMC init time and not updated later when we change the MIF
853*4882a593Smuzhiyun * voltage based on ASV group in kernel. Applying MC-initiated mode
854*4882a593Smuzhiyun * makes sure that DLL tracing is ON so that silicon is able to
855*4882a593Smuzhiyun * compensate the voltage variation.
856*4882a593Smuzhiyun */
857*4882a593Smuzhiyun val = readl(&drex0->concontrol);
858*4882a593Smuzhiyun val |= CONCONTROL_UPDATE_MODE;
859*4882a593Smuzhiyun writel(val, &drex0->concontrol);
860*4882a593Smuzhiyun val = readl(&drex1->concontrol);
861*4882a593Smuzhiyun val |= CONCONTROL_UPDATE_MODE;
862*4882a593Smuzhiyun writel(val, &drex1->concontrol);
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun return 0;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun #endif
867