blob: f2c228d339d966e987918aca3fb4830feb2afefb [file] [log] [blame]
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -08001/*
Stefan Reinauer08dc3572013-05-14 16:57:50 -07002 * This file is part of the coreboot project.
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -08003 *
4 * Copyright (C) 2012 Samsung Electronics
5 *
Stefan Reinauer08dc3572013-05-14 16:57:50 -07006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -08009 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Stefan Reinauer08dc3572013-05-14 16:57:50 -070017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080018 */
19
Stefan Reinauer08dc3572013-05-14 16:57:50 -070020/* DDR3 mem setup file for SMDK5250 board based on EXYNOS5 */
21
22#include <console/console.h>
David Hendricks1fb11d12013-04-12 15:11:05 -070023#include <delay.h>
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080024#include <arch/io.h>
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080025#include "clk.h"
26#include "cpu.h"
27#include "dmc.h"
28#include "setup.h"
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080029
30#define RDLVL_COMPLETE_TIMEOUT 10000
31
32static void reset_phy_ctrl(void)
33{
34 struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
35
Hung-Te Linc5aac952013-07-08 18:41:02 +080036 writel(LPDDR3PHY_CTRL_PHY_RESET_ENABLE, &clk->lpddr3phy_ctrl);
37 writel(LPDDR3PHY_CTRL_PHY_RESET_DISABLE, &clk->lpddr3phy_ctrl);
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080038
David Hendricks1fb11d12013-04-12 15:11:05 -070039#if 0
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080040 /*
41 * For proper memory initialization there should be a minimum delay of
42 * 500us after the LPDDR3PHY_CTRL_PHY_RESET signal.
43 * The below value is an approximate value whose calculation in done
44 * considering that sdelay takes 2 instruction for every 1 delay cycle.
45 * And assuming each instruction takes 1 clock cycle i.e 1/(1.7 Ghz)sec
46 * So for 500 usec, the number of delay cycle should be
47 * (500 * 10^-6) * (1.7 * 10^9) / 2 = 425000
48 *
49 * TODO(hatim.rv@samsung.com): Implement the delay using timer/counter
50 */
51 sdelay(425000);
David Hendricks1fb11d12013-04-12 15:11:05 -070052#endif
53 udelay(500);
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080054}
55
Hung-Te Lin55c753d2013-04-25 16:14:19 +080056int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
57 int mem_reset)
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080058{
59 unsigned int val;
60 struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl;
61 struct exynos5_dmc *dmc;
62 int i;
63
64 phy0_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY0_BASE;
65 phy1_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY1_BASE;
66 dmc = (struct exynos5_dmc *)EXYNOS5_DMC_CTRL_BASE;
Hung-Te Lin55c753d2013-04-25 16:14:19 +080067
Ronald G. Minnich6da70462013-06-26 09:51:21 -070068 if (mem_reset)
Hung-Te Lin55c753d2013-04-25 16:14:19 +080069 reset_phy_ctrl();
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080070
71 /* Set Impedance Output Driver */
72 val = (mem->impedance << CA_CK_DRVR_DS_OFFSET) |
73 (mem->impedance << CA_CKE_DRVR_DS_OFFSET) |
74 (mem->impedance << CA_CS_DRVR_DS_OFFSET) |
75 (mem->impedance << CA_ADR_DRVR_DS_OFFSET);
76 writel(val, &phy0_ctrl->phy_con39);
77 writel(val, &phy1_ctrl->phy_con39);
78
79 /* Set Read Latency and Burst Length for PHY0 and PHY1 */
80 val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) |
81 (mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT);
82 writel(val, &phy0_ctrl->phy_con42);
83 writel(val, &phy1_ctrl->phy_con42);
84
85 /* ZQ Calibration */
Ronald G. Minnich6da70462013-06-26 09:51:21 -070086 if (dmc_config_zq(mem, phy0_ctrl, phy1_ctrl)) {
87 printk(BIOS_EMERG, "DRAM ZQ CALIBRATION FAILURE\n");
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080088 return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
Ronald G. Minnich6da70462013-06-26 09:51:21 -070089 }
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -080090
91 /* DQ Signal */
92 writel(mem->phy0_pulld_dqs, &phy0_ctrl->phy_con14);
93 writel(mem->phy1_pulld_dqs, &phy1_ctrl->phy_con14);
94
95 writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
96 | (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT),
97 &dmc->concontrol);
98
99 update_reset_dll(dmc, DDR_MODE_DDR3);
100
101 /* DQS Signal */
102 writel(mem->phy0_dqs, &phy0_ctrl->phy_con4);
103 writel(mem->phy1_dqs, &phy1_ctrl->phy_con4);
104
105 writel(mem->phy0_dq, &phy0_ctrl->phy_con6);
106 writel(mem->phy1_dq, &phy1_ctrl->phy_con6);
107
108 writel(mem->phy0_tFS, &phy0_ctrl->phy_con10);
109 writel(mem->phy1_tFS, &phy1_ctrl->phy_con10);
110
111 val = (mem->ctrl_start_point << PHY_CON12_CTRL_START_POINT_SHIFT) |
112 (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
113 (mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
114 (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
115 writel(val, &phy0_ctrl->phy_con12);
116 writel(val, &phy1_ctrl->phy_con12);
117
118 /* Start DLL locking */
119 writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
120 &phy0_ctrl->phy_con12);
121 writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
122 &phy1_ctrl->phy_con12);
123
124 update_reset_dll(dmc, DDR_MODE_DDR3);
125
126 writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
127 &dmc->concontrol);
128
Martin Roth4c3ab732013-07-08 16:23:54 -0600129 /* Memory Channel Interleaving Size */
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -0800130 writel(mem->iv_size, &dmc->ivcontrol);
131
132 /* Set DMC MEMCONTROL register */
133 val = mem->memcontrol & ~DMC_MEMCONTROL_DSREF_ENABLE;
134 writel(val, &dmc->memcontrol);
135
136 writel(mem->memconfig, &dmc->memconfig0);
137 writel(mem->memconfig, &dmc->memconfig1);
138 writel(mem->membaseconfig0, &dmc->membaseconfig0);
139 writel(mem->membaseconfig1, &dmc->membaseconfig1);
140
141 /* Precharge Configuration */
142 writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
143 &dmc->prechconfig);
144
145 /* Power Down mode Configuration */
146 writel(mem->dpwrdn_cyc << PWRDNCONFIG_DPWRDN_CYC_SHIFT |
147 mem->dsref_cyc << PWRDNCONFIG_DSREF_CYC_SHIFT,
148 &dmc->pwrdnconfig);
149
150 /* TimingRow, TimingData, TimingPower and Timingaref
151 * values as per Memory AC parameters
152 */
153 writel(mem->timing_ref, &dmc->timingref);
154 writel(mem->timing_row, &dmc->timingrow);
155 writel(mem->timing_data, &dmc->timingdata);
156 writel(mem->timing_power, &dmc->timingpower);
157
158 /* Send PALL command */
159 dmc_config_prech(mem, dmc);
160
Hung-Te Linc0491d42013-08-06 10:48:48 +0800161 if (mem_reset) {
162 /* Send NOP, MRS and ZQINIT commands.
163 * Sending MRS command will reset the DRAM. We should not be
164 * reseting the DRAM after resume, this will lead to memory
165 * corruption as DRAM content is lost after DRAM reset
166 */
167 dmc_config_mrs(mem, dmc);
168 }
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -0800169
170 if (mem->gate_leveling_enable) {
171 val = PHY_CON0_RESET_VAL;
172 val |= P0_CMD_EN;
173 writel(val, &phy0_ctrl->phy_con0);
174 writel(val, &phy1_ctrl->phy_con0);
175
176 val = PHY_CON2_RESET_VAL;
177 val |= INIT_DESKEW_EN;
178 writel(val, &phy0_ctrl->phy_con2);
179 writel(val, &phy1_ctrl->phy_con2);
180
181 val = PHY_CON0_RESET_VAL;
182 val |= P0_CMD_EN;
183 val |= BYTE_RDLVL_EN;
184 writel(val, &phy0_ctrl->phy_con0);
185 writel(val, &phy1_ctrl->phy_con0);
186
187 val = (mem->ctrl_start_point <<
188 PHY_CON12_CTRL_START_POINT_SHIFT) |
189 (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
190 (mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
191 (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
192 (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
193 writel(val, &phy0_ctrl->phy_con12);
194 writel(val, &phy1_ctrl->phy_con12);
195
196 val = PHY_CON2_RESET_VAL;
197 val |= INIT_DESKEW_EN;
198 val |= RDLVL_GATE_EN;
199 writel(val, &phy0_ctrl->phy_con2);
200 writel(val, &phy1_ctrl->phy_con2);
201
202 val = PHY_CON0_RESET_VAL;
203 val |= P0_CMD_EN;
204 val |= BYTE_RDLVL_EN;
205 val |= CTRL_SHGATE;
206 writel(val, &phy0_ctrl->phy_con0);
207 writel(val, &phy1_ctrl->phy_con0);
208
209 val = PHY_CON1_RESET_VAL;
210 val &= ~(CTRL_GATEDURADJ_MASK);
211 writel(val, &phy0_ctrl->phy_con1);
212 writel(val, &phy1_ctrl->phy_con1);
213
214 writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config);
215 i = RDLVL_COMPLETE_TIMEOUT;
216 while ((readl(&dmc->phystatus) &
217 (RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) !=
218 (RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) {
219 /*
220 * TODO(waihong): Comment on how long this take to
221 * timeout
222 */
David Hendricks1fb11d12013-04-12 15:11:05 -0700223 udelay(1);
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -0800224 i--;
225 }
Ronald G. Minnich88e46912013-01-29 14:16:35 -0800226 if (!i){
Ronald G. Minnich6da70462013-06-26 09:51:21 -0700227 printk(BIOS_EMERG, "Timeout on RDLVL. No DRAM.\n");
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -0800228 return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
Ronald G. Minnich88e46912013-01-29 14:16:35 -0800229 }
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -0800230 writel(CTRL_RDLVL_GATE_DISABLE, &dmc->rdlvl_config);
231
232 writel(0, &phy0_ctrl->phy_con14);
233 writel(0, &phy1_ctrl->phy_con14);
234
235 val = (mem->ctrl_start_point <<
236 PHY_CON12_CTRL_START_POINT_SHIFT) |
237 (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
238 (mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
239 (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
240 (mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
241 (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
242 writel(val, &phy0_ctrl->phy_con12);
243 writel(val, &phy1_ctrl->phy_con12);
244
245 update_reset_dll(dmc, DDR_MODE_DDR3);
246 }
247
248 /* Send PALL command */
249 dmc_config_prech(mem, dmc);
250
251 writel(mem->memcontrol, &dmc->memcontrol);
252
253 /* Set DMC Concontrol and enable auto-refresh counter */
Stefan Reinauer9fe20cb2012-12-07 17:18:43 -0800254 writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
255 | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT), &dmc->concontrol);
256 return 0;
257}