1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright 2021 NXP
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park *
6*54fd6939SJiyong Park */
7*54fd6939SJiyong Park
8*54fd6939SJiyong Park #include <errno.h>
9*54fd6939SJiyong Park #include <stdbool.h>
10*54fd6939SJiyong Park #include <stdint.h>
11*54fd6939SJiyong Park #include <stdio.h>
12*54fd6939SJiyong Park #include <stdlib.h>
13*54fd6939SJiyong Park
14*54fd6939SJiyong Park #include <common/debug.h>
15*54fd6939SJiyong Park #include <ddr.h>
16*54fd6939SJiyong Park #include <lib/utils.h>
17*54fd6939SJiyong Park
cal_cwl(const unsigned long clk)18*54fd6939SJiyong Park static inline unsigned int cal_cwl(const unsigned long clk)
19*54fd6939SJiyong Park {
20*54fd6939SJiyong Park const unsigned int mclk_ps = get_memory_clk_ps(clk);
21*54fd6939SJiyong Park
22*54fd6939SJiyong Park return mclk_ps >= 1250U ? 9U :
23*54fd6939SJiyong Park (mclk_ps >= 1070U ? 10U :
24*54fd6939SJiyong Park (mclk_ps >= 935U ? 11U :
25*54fd6939SJiyong Park (mclk_ps >= 833U ? 12U :
26*54fd6939SJiyong Park (mclk_ps >= 750U ? 14U :
27*54fd6939SJiyong Park (mclk_ps >= 625U ? 16U : 18U)))));
28*54fd6939SJiyong Park }
29*54fd6939SJiyong Park
cal_csn_config(int i,struct ddr_cfg_regs * regs,const struct memctl_opt * popts,const struct dimm_params * pdimm)30*54fd6939SJiyong Park static void cal_csn_config(int i,
31*54fd6939SJiyong Park struct ddr_cfg_regs *regs,
32*54fd6939SJiyong Park const struct memctl_opt *popts,
33*54fd6939SJiyong Park const struct dimm_params *pdimm)
34*54fd6939SJiyong Park {
35*54fd6939SJiyong Park unsigned int intlv_en = 0U;
36*54fd6939SJiyong Park unsigned int intlv_ctl = 0U;
37*54fd6939SJiyong Park const unsigned int cs_n_en = 1U;
38*54fd6939SJiyong Park const unsigned int ap_n_en = popts->cs_odt[i].auto_precharge;
39*54fd6939SJiyong Park const unsigned int odt_rd_cfg = popts->cs_odt[i].odt_rd_cfg;
40*54fd6939SJiyong Park const unsigned int odt_wr_cfg = popts->cs_odt[i].odt_wr_cfg;
41*54fd6939SJiyong Park const unsigned int ba_bits_cs_n = pdimm->bank_addr_bits;
42*54fd6939SJiyong Park const unsigned int row_bits_cs_n = pdimm->n_row_addr - 12U;
43*54fd6939SJiyong Park const unsigned int col_bits_cs_n = pdimm->n_col_addr - 8U;
44*54fd6939SJiyong Park const unsigned int bg_bits_cs_n = pdimm->bank_group_bits;
45*54fd6939SJiyong Park
46*54fd6939SJiyong Park if (i == 0) {
47*54fd6939SJiyong Park /* These fields only available in CS0_CONFIG */
48*54fd6939SJiyong Park if (popts->ctlr_intlv != 0) {
49*54fd6939SJiyong Park switch (popts->ctlr_intlv_mode) {
50*54fd6939SJiyong Park case DDR_256B_INTLV:
51*54fd6939SJiyong Park intlv_en = popts->ctlr_intlv;
52*54fd6939SJiyong Park intlv_ctl = popts->ctlr_intlv_mode;
53*54fd6939SJiyong Park break;
54*54fd6939SJiyong Park default:
55*54fd6939SJiyong Park break;
56*54fd6939SJiyong Park }
57*54fd6939SJiyong Park }
58*54fd6939SJiyong Park }
59*54fd6939SJiyong Park regs->cs[i].config = ((cs_n_en & 0x1) << 31) |
60*54fd6939SJiyong Park ((intlv_en & 0x3) << 29) |
61*54fd6939SJiyong Park ((intlv_ctl & 0xf) << 24) |
62*54fd6939SJiyong Park ((ap_n_en & 0x1) << 23) |
63*54fd6939SJiyong Park ((odt_rd_cfg & 0x7) << 20) |
64*54fd6939SJiyong Park ((odt_wr_cfg & 0x7) << 16) |
65*54fd6939SJiyong Park ((ba_bits_cs_n & 0x3) << 14) |
66*54fd6939SJiyong Park ((row_bits_cs_n & 0x7) << 8) |
67*54fd6939SJiyong Park ((bg_bits_cs_n & 0x3) << 4) |
68*54fd6939SJiyong Park ((col_bits_cs_n & 0x7) << 0);
69*54fd6939SJiyong Park debug("cs%d\n", i);
70*54fd6939SJiyong Park debug(" _config = 0x%x\n", regs->cs[i].config);
71*54fd6939SJiyong Park }
72*54fd6939SJiyong Park
avoid_odt_overlap(const struct ddr_conf * conf,const struct dimm_params * pdimm)73*54fd6939SJiyong Park static inline int avoid_odt_overlap(const struct ddr_conf *conf,
74*54fd6939SJiyong Park const struct dimm_params *pdimm)
75*54fd6939SJiyong Park {
76*54fd6939SJiyong Park if ((conf->cs_in_use == 0xf) != 0) {
77*54fd6939SJiyong Park return 2;
78*54fd6939SJiyong Park }
79*54fd6939SJiyong Park
80*54fd6939SJiyong Park #if DDRC_NUM_DIMM >= 2
81*54fd6939SJiyong Park if (conf->dimm_in_use[0] != 0 && conf->dimm_in_use[1] != 0) {
82*54fd6939SJiyong Park return 1;
83*54fd6939SJiyong Park }
84*54fd6939SJiyong Park #endif
85*54fd6939SJiyong Park return 0;
86*54fd6939SJiyong Park }
87*54fd6939SJiyong Park
88*54fd6939SJiyong Park /* Requires rcw2 set first */
cal_timing_cfg(const unsigned long clk,struct ddr_cfg_regs * regs,const struct memctl_opt * popts,const struct dimm_params * pdimm,const struct ddr_conf * conf,unsigned int cas_latency,unsigned int additive_latency)89*54fd6939SJiyong Park static void cal_timing_cfg(const unsigned long clk,
90*54fd6939SJiyong Park struct ddr_cfg_regs *regs,
91*54fd6939SJiyong Park const struct memctl_opt *popts,
92*54fd6939SJiyong Park const struct dimm_params *pdimm,
93*54fd6939SJiyong Park const struct ddr_conf *conf,
94*54fd6939SJiyong Park unsigned int cas_latency,
95*54fd6939SJiyong Park unsigned int additive_latency)
96*54fd6939SJiyong Park {
97*54fd6939SJiyong Park const unsigned int mclk_ps = get_memory_clk_ps(clk);
98*54fd6939SJiyong Park /* tXP=max(4nCK, 6ns) */
99*54fd6939SJiyong Park const int txp = max((int)mclk_ps * 4, 6000);
100*54fd6939SJiyong Park /* DDR4 supports 10, 12, 14, 16, 18, 20, 24 */
101*54fd6939SJiyong Park static const int wrrec_table[] = {
102*54fd6939SJiyong Park 10, 10, 10, 10, 10,
103*54fd6939SJiyong Park 10, 10, 10, 10, 10,
104*54fd6939SJiyong Park 12, 12, 14, 14, 16,
105*54fd6939SJiyong Park 16, 18, 18, 20, 20,
106*54fd6939SJiyong Park 24, 24, 24, 24,
107*54fd6939SJiyong Park };
108*54fd6939SJiyong Park int trwt_mclk = (clk / 1000000 > 1900) ? 3 : 2;
109*54fd6939SJiyong Park int twrt_mclk;
110*54fd6939SJiyong Park int trrt_mclk;
111*54fd6939SJiyong Park int twwt_mclk;
112*54fd6939SJiyong Park const int act_pd_exit_mclk = picos_to_mclk(clk, txp);
113*54fd6939SJiyong Park const int pre_pd_exit_mclk = act_pd_exit_mclk;
114*54fd6939SJiyong Park const int taxpd_mclk = 0;
115*54fd6939SJiyong Park /*
116*54fd6939SJiyong Park * MRS_CYC = max(tMRD, tMOD)
117*54fd6939SJiyong Park * tMRD = 8nCK, tMOD = max(24nCK, 15ns)
118*54fd6939SJiyong Park */
119*54fd6939SJiyong Park const int tmrd_mclk = max(24U, picos_to_mclk(clk, 15000));
120*54fd6939SJiyong Park const int pretoact_mclk = picos_to_mclk(clk, pdimm->trp_ps);
121*54fd6939SJiyong Park const int acttopre_mclk = picos_to_mclk(clk, pdimm->tras_ps);
122*54fd6939SJiyong Park const int acttorw_mclk = picos_to_mclk(clk, pdimm->trcd_ps);
123*54fd6939SJiyong Park const int caslat_ctrl = (cas_latency - 1) << 1;
124*54fd6939SJiyong Park const int trfc1_min = pdimm->die_density >= 0x3 ? 16000 :
125*54fd6939SJiyong Park (pdimm->die_density == 0x4 ? 26000 :
126*54fd6939SJiyong Park (pdimm->die_density == 0x5 ? 35000 :
127*54fd6939SJiyong Park 55000));
128*54fd6939SJiyong Park const int refrec_ctrl = picos_to_mclk(clk,
129*54fd6939SJiyong Park pdimm->trfc1_ps) - 8;
130*54fd6939SJiyong Park int wrrec_mclk = picos_to_mclk(clk, pdimm->twr_ps);
131*54fd6939SJiyong Park const int acttoact_mclk = max(picos_to_mclk(clk,
132*54fd6939SJiyong Park pdimm->trrds_ps),
133*54fd6939SJiyong Park 4U);
134*54fd6939SJiyong Park int wrtord_mclk = max(2U, picos_to_mclk(clk, 2500));
135*54fd6939SJiyong Park const unsigned int cpo = 0U;
136*54fd6939SJiyong Park const int wr_lat = cal_cwl(clk);
137*54fd6939SJiyong Park int rd_to_pre = picos_to_mclk(clk, 7500);
138*54fd6939SJiyong Park const int wr_data_delay = popts->wr_data_delay;
139*54fd6939SJiyong Park const int cke_pls = max(3U, picos_to_mclk(clk, 5000));
140*54fd6939SJiyong Park #ifdef ERRATA_DDR_A050450
141*54fd6939SJiyong Park const unsigned short four_act = ((popts->twot_en == 0) &&
142*54fd6939SJiyong Park (popts->threet_en == 0) &&
143*54fd6939SJiyong Park (popts->tfaw_ps % 2 == 0)) ?
144*54fd6939SJiyong Park (picos_to_mclk(clk, popts->tfaw_ps) + 1) :
145*54fd6939SJiyong Park picos_to_mclk(clk, popts->tfaw_ps);
146*54fd6939SJiyong Park #else
147*54fd6939SJiyong Park const unsigned short four_act = picos_to_mclk(clk,
148*54fd6939SJiyong Park popts->tfaw_ps);
149*54fd6939SJiyong Park #endif
150*54fd6939SJiyong Park const unsigned int cntl_adj = 0U;
151*54fd6939SJiyong Park const unsigned int ext_pretoact = picos_to_mclk(clk,
152*54fd6939SJiyong Park pdimm->trp_ps) >> 4U;
153*54fd6939SJiyong Park const unsigned int ext_acttopre = picos_to_mclk(clk,
154*54fd6939SJiyong Park pdimm->tras_ps) >> 4U;
155*54fd6939SJiyong Park const unsigned int ext_acttorw = picos_to_mclk(clk,
156*54fd6939SJiyong Park pdimm->trcd_ps) >> 4U;
157*54fd6939SJiyong Park const unsigned int ext_caslat = (2U * cas_latency - 1U) >> 4U;
158*54fd6939SJiyong Park const unsigned int ext_add_lat = additive_latency >> 4U;
159*54fd6939SJiyong Park const unsigned int ext_refrec = (picos_to_mclk(clk,
160*54fd6939SJiyong Park pdimm->trfc1_ps) - 8U) >> 4U;
161*54fd6939SJiyong Park const unsigned int ext_wrrec = (picos_to_mclk(clk, pdimm->twr_ps) +
162*54fd6939SJiyong Park (popts->otf_burst_chop_en ? 2U : 0U)) >> 4U;
163*54fd6939SJiyong Park const unsigned int rwt_same_cs = 0U;
164*54fd6939SJiyong Park const unsigned int wrt_same_cs = 0U;
165*54fd6939SJiyong Park const unsigned int rrt_same_cs = popts->burst_length == DDR_BL8 ? 0U : 2U;
166*54fd6939SJiyong Park const unsigned int wwt_same_cs = popts->burst_length == DDR_BL8 ? 0U : 2U;
167*54fd6939SJiyong Park const unsigned int dll_lock = 2U;
168*54fd6939SJiyong Park unsigned int rodt_on = 0U;
169*54fd6939SJiyong Park const unsigned int rodt_off = 4U;
170*54fd6939SJiyong Park const unsigned int wodt_on = 1U;
171*54fd6939SJiyong Park const unsigned int wodt_off = 4U;
172*54fd6939SJiyong Park const unsigned int hs_caslat = 0U;
173*54fd6939SJiyong Park const unsigned int hs_wrlat = 0U;
174*54fd6939SJiyong Park const unsigned int hs_wrrec = 0U;
175*54fd6939SJiyong Park const unsigned int hs_clkadj = 0U;
176*54fd6939SJiyong Park const unsigned int hs_wrlvl_start = 0U;
177*54fd6939SJiyong Park const unsigned int txpr = max(5U,
178*54fd6939SJiyong Park picos_to_mclk(clk,
179*54fd6939SJiyong Park pdimm->trfc1_ps + 10000U));
180*54fd6939SJiyong Park const unsigned int tcksre = max(5U, picos_to_mclk(clk, 10000U));
181*54fd6939SJiyong Park const unsigned int tcksrx = max(5U, picos_to_mclk(clk, 10000U));
182*54fd6939SJiyong Park const unsigned int cs_to_cmd = 0U;
183*54fd6939SJiyong Park const unsigned int cke_rst = txpr <= 200U ? 0U :
184*54fd6939SJiyong Park (txpr <= 256U ? 1U :
185*54fd6939SJiyong Park (txpr <= 512U ? 2U : 3U));
186*54fd6939SJiyong Park const unsigned int cksre = tcksre <= 19U ? tcksre - 5U : 15U;
187*54fd6939SJiyong Park const unsigned int cksrx = tcksrx <= 19U ? tcksrx - 5U : 15U;
188*54fd6939SJiyong Park unsigned int par_lat = 0U;
189*54fd6939SJiyong Park const int tccdl = max(5U, picos_to_mclk(clk, pdimm->tccdl_ps));
190*54fd6939SJiyong Park int rwt_bg = cas_latency + 2 + 4 - wr_lat;
191*54fd6939SJiyong Park int wrt_bg = wr_lat + 4 + 1 - cas_latency;
192*54fd6939SJiyong Park const int rrt_bg = popts->burst_length == DDR_BL8 ?
193*54fd6939SJiyong Park tccdl - 4 : tccdl - 2;
194*54fd6939SJiyong Park const int wwt_bg = popts->burst_length == DDR_BL8 ?
195*54fd6939SJiyong Park tccdl - 4 : tccdl - 2;
196*54fd6939SJiyong Park const unsigned int acttoact_bg = picos_to_mclk(clk, pdimm->trrdl_ps);
197*54fd6939SJiyong Park const unsigned int wrtord_bg = max(4U, picos_to_mclk(clk, 7500)) +
198*54fd6939SJiyong Park (popts->otf_burst_chop_en ? 2 : 0);
199*54fd6939SJiyong Park const unsigned int pre_all_rec = 0;
200*54fd6939SJiyong Park const unsigned int refrec_cid_mclk = pdimm->package_3ds ?
201*54fd6939SJiyong Park picos_to_mclk(clk, pdimm->trfc_slr_ps) : 0;
202*54fd6939SJiyong Park const unsigned int acttoact_cid_mclk = pdimm->package_3ds ? 4U : 0;
203*54fd6939SJiyong Park
204*54fd6939SJiyong Park
205*54fd6939SJiyong Park /* for two dual-rank DIMMs to avoid ODT overlap */
206*54fd6939SJiyong Park if (avoid_odt_overlap(conf, pdimm) == 2) {
207*54fd6939SJiyong Park twrt_mclk = 2;
208*54fd6939SJiyong Park twwt_mclk = 2;
209*54fd6939SJiyong Park trrt_mclk = 2;
210*54fd6939SJiyong Park } else {
211*54fd6939SJiyong Park twrt_mclk = 1;
212*54fd6939SJiyong Park twwt_mclk = 1;
213*54fd6939SJiyong Park trrt_mclk = 0;
214*54fd6939SJiyong Park }
215*54fd6939SJiyong Park
216*54fd6939SJiyong Park if (popts->trwt_override != 0) {
217*54fd6939SJiyong Park trwt_mclk = popts->trwt;
218*54fd6939SJiyong Park if (popts->twrt != 0) {
219*54fd6939SJiyong Park twrt_mclk = popts->twrt;
220*54fd6939SJiyong Park }
221*54fd6939SJiyong Park if (popts->trrt != 0) {
222*54fd6939SJiyong Park trrt_mclk = popts->trrt;
223*54fd6939SJiyong Park }
224*54fd6939SJiyong Park if (popts->twwt != 0) {
225*54fd6939SJiyong Park twwt_mclk = popts->twwt;
226*54fd6939SJiyong Park }
227*54fd6939SJiyong Park }
228*54fd6939SJiyong Park regs->timing_cfg[0] = (((trwt_mclk & 0x3) << 30) |
229*54fd6939SJiyong Park ((twrt_mclk & 0x3) << 28) |
230*54fd6939SJiyong Park ((trrt_mclk & 0x3) << 26) |
231*54fd6939SJiyong Park ((twwt_mclk & 0x3) << 24) |
232*54fd6939SJiyong Park ((act_pd_exit_mclk & 0xf) << 20) |
233*54fd6939SJiyong Park ((pre_pd_exit_mclk & 0xF) << 16) |
234*54fd6939SJiyong Park ((taxpd_mclk & 0xf) << 8) |
235*54fd6939SJiyong Park ((tmrd_mclk & 0x1f) << 0));
236*54fd6939SJiyong Park debug("timing_cfg[0] = 0x%x\n", regs->timing_cfg[0]);
237*54fd6939SJiyong Park
238*54fd6939SJiyong Park if ((wrrec_mclk < 1) || (wrrec_mclk > 24)) {
239*54fd6939SJiyong Park ERROR("WRREC doesn't support clock %d\n", wrrec_mclk);
240*54fd6939SJiyong Park } else {
241*54fd6939SJiyong Park wrrec_mclk = wrrec_table[wrrec_mclk - 1];
242*54fd6939SJiyong Park }
243*54fd6939SJiyong Park
244*54fd6939SJiyong Park if (popts->otf_burst_chop_en != 0) {
245*54fd6939SJiyong Park wrrec_mclk += 2;
246*54fd6939SJiyong Park wrtord_mclk += 2;
247*54fd6939SJiyong Park }
248*54fd6939SJiyong Park
249*54fd6939SJiyong Park if (pdimm->trfc1_ps < trfc1_min) {
250*54fd6939SJiyong Park ERROR("trfc1_ps (%d) < %d\n", pdimm->trfc1_ps, trfc1_min);
251*54fd6939SJiyong Park }
252*54fd6939SJiyong Park
253*54fd6939SJiyong Park regs->timing_cfg[1] = (((pretoact_mclk & 0x0F) << 28) |
254*54fd6939SJiyong Park ((acttopre_mclk & 0x0F) << 24) |
255*54fd6939SJiyong Park ((acttorw_mclk & 0xF) << 20) |
256*54fd6939SJiyong Park ((caslat_ctrl & 0xF) << 16) |
257*54fd6939SJiyong Park ((refrec_ctrl & 0xF) << 12) |
258*54fd6939SJiyong Park ((wrrec_mclk & 0x0F) << 8) |
259*54fd6939SJiyong Park ((acttoact_mclk & 0x0F) << 4) |
260*54fd6939SJiyong Park ((wrtord_mclk & 0x0F) << 0));
261*54fd6939SJiyong Park debug("timing_cfg[1] = 0x%x\n", regs->timing_cfg[1]);
262*54fd6939SJiyong Park
263*54fd6939SJiyong Park if (rd_to_pre < 4) {
264*54fd6939SJiyong Park rd_to_pre = 4;
265*54fd6939SJiyong Park }
266*54fd6939SJiyong Park if (popts->otf_burst_chop_en) {
267*54fd6939SJiyong Park rd_to_pre += 2;
268*54fd6939SJiyong Park }
269*54fd6939SJiyong Park
270*54fd6939SJiyong Park regs->timing_cfg[2] = (((additive_latency & 0xf) << 28) |
271*54fd6939SJiyong Park ((cpo & 0x1f) << 23) |
272*54fd6939SJiyong Park ((wr_lat & 0xf) << 19) |
273*54fd6939SJiyong Park (((wr_lat & 0x10) >> 4) << 18) |
274*54fd6939SJiyong Park ((rd_to_pre & 0xf) << 13) |
275*54fd6939SJiyong Park ((wr_data_delay & 0xf) << 9) |
276*54fd6939SJiyong Park ((cke_pls & 0x7) << 6) |
277*54fd6939SJiyong Park ((four_act & 0x3f) << 0));
278*54fd6939SJiyong Park debug("timing_cfg[2] = 0x%x\n", regs->timing_cfg[2]);
279*54fd6939SJiyong Park
280*54fd6939SJiyong Park regs->timing_cfg[3] = (((ext_pretoact & 0x1) << 28) |
281*54fd6939SJiyong Park ((ext_acttopre & 0x3) << 24) |
282*54fd6939SJiyong Park ((ext_acttorw & 0x1) << 22) |
283*54fd6939SJiyong Park ((ext_refrec & 0x3F) << 16) |
284*54fd6939SJiyong Park ((ext_caslat & 0x3) << 12) |
285*54fd6939SJiyong Park ((ext_add_lat & 0x1) << 10) |
286*54fd6939SJiyong Park ((ext_wrrec & 0x1) << 8) |
287*54fd6939SJiyong Park ((cntl_adj & 0x7) << 0));
288*54fd6939SJiyong Park debug("timing_cfg[3] = 0x%x\n", regs->timing_cfg[3]);
289*54fd6939SJiyong Park
290*54fd6939SJiyong Park regs->timing_cfg[4] = (((rwt_same_cs & 0xf) << 28) |
291*54fd6939SJiyong Park ((wrt_same_cs & 0xf) << 24) |
292*54fd6939SJiyong Park ((rrt_same_cs & 0xf) << 20) |
293*54fd6939SJiyong Park ((wwt_same_cs & 0xf) << 16) |
294*54fd6939SJiyong Park ((trwt_mclk & 0xc) << 12) |
295*54fd6939SJiyong Park ((twrt_mclk & 0x4) << 10) |
296*54fd6939SJiyong Park ((trrt_mclk & 0x4) << 8) |
297*54fd6939SJiyong Park ((twwt_mclk & 0x4) << 6) |
298*54fd6939SJiyong Park (dll_lock & 0x3));
299*54fd6939SJiyong Park debug("timing_cfg[4] = 0x%x\n", regs->timing_cfg[4]);
300*54fd6939SJiyong Park
301*54fd6939SJiyong Park /* rodt_on = timing_cfg_1[caslat] - timing_cfg_2[wrlat] + 1 */
302*54fd6939SJiyong Park if (cas_latency >= wr_lat) {
303*54fd6939SJiyong Park rodt_on = cas_latency - wr_lat + 1;
304*54fd6939SJiyong Park }
305*54fd6939SJiyong Park
306*54fd6939SJiyong Park regs->timing_cfg[5] = (((rodt_on & 0x1f) << 24) |
307*54fd6939SJiyong Park ((rodt_off & 0x7) << 20) |
308*54fd6939SJiyong Park ((wodt_on & 0x1f) << 12) |
309*54fd6939SJiyong Park (wodt_off & 0x7) << 8);
310*54fd6939SJiyong Park debug("timing_cfg[5] = 0x%x\n", regs->timing_cfg[5]);
311*54fd6939SJiyong Park
312*54fd6939SJiyong Park regs->timing_cfg[6] = (((hs_caslat & 0x1f) << 24) |
313*54fd6939SJiyong Park ((hs_wrlat & 0x1f) << 19) |
314*54fd6939SJiyong Park ((hs_wrrec & 0x1f) << 12) |
315*54fd6939SJiyong Park ((hs_clkadj & 0x1f) << 6) |
316*54fd6939SJiyong Park ((hs_wrlvl_start & 0x1f) << 0));
317*54fd6939SJiyong Park debug("timing_cfg[6] = 0x%x\n", regs->timing_cfg[6]);
318*54fd6939SJiyong Park
319*54fd6939SJiyong Park if (popts->ap_en != 0) {
320*54fd6939SJiyong Park par_lat = (regs->sdram_rcw[1] & 0xf) + 1;
321*54fd6939SJiyong Park debug("PAR_LAT = 0x%x\n", par_lat);
322*54fd6939SJiyong Park }
323*54fd6939SJiyong Park
324*54fd6939SJiyong Park regs->timing_cfg[7] = (((cke_rst & 0x3) << 28) |
325*54fd6939SJiyong Park ((cksre & 0xf) << 24) |
326*54fd6939SJiyong Park ((cksrx & 0xf) << 20) |
327*54fd6939SJiyong Park ((par_lat & 0xf) << 16) |
328*54fd6939SJiyong Park ((cs_to_cmd & 0xf) << 4));
329*54fd6939SJiyong Park debug("timing_cfg[7] = 0x%x\n", regs->timing_cfg[7]);
330*54fd6939SJiyong Park
331*54fd6939SJiyong Park if (rwt_bg < tccdl) {
332*54fd6939SJiyong Park rwt_bg = tccdl - rwt_bg;
333*54fd6939SJiyong Park } else {
334*54fd6939SJiyong Park rwt_bg = 0;
335*54fd6939SJiyong Park }
336*54fd6939SJiyong Park if (wrt_bg < tccdl) {
337*54fd6939SJiyong Park wrt_bg = tccdl - wrt_bg;
338*54fd6939SJiyong Park } else {
339*54fd6939SJiyong Park wrt_bg = 0;
340*54fd6939SJiyong Park }
341*54fd6939SJiyong Park regs->timing_cfg[8] = (((rwt_bg & 0xf) << 28) |
342*54fd6939SJiyong Park ((wrt_bg & 0xf) << 24) |
343*54fd6939SJiyong Park ((rrt_bg & 0xf) << 20) |
344*54fd6939SJiyong Park ((wwt_bg & 0xf) << 16) |
345*54fd6939SJiyong Park ((acttoact_bg & 0xf) << 12) |
346*54fd6939SJiyong Park ((wrtord_bg & 0xf) << 8) |
347*54fd6939SJiyong Park ((pre_all_rec & 0x1f) << 0));
348*54fd6939SJiyong Park debug("timing_cfg[8] = 0x%x\n", regs->timing_cfg[8]);
349*54fd6939SJiyong Park
350*54fd6939SJiyong Park regs->timing_cfg[9] = (refrec_cid_mclk & 0x3ff) << 16 |
351*54fd6939SJiyong Park (acttoact_cid_mclk & 0xf) << 8;
352*54fd6939SJiyong Park debug("timing_cfg[9] = 0x%x\n", regs->timing_cfg[9]);
353*54fd6939SJiyong Park }
354*54fd6939SJiyong Park
cal_ddr_sdram_rcw(const unsigned long clk,struct ddr_cfg_regs * regs,const struct memctl_opt * popts,const struct dimm_params * pdimm)355*54fd6939SJiyong Park static void cal_ddr_sdram_rcw(const unsigned long clk,
356*54fd6939SJiyong Park struct ddr_cfg_regs *regs,
357*54fd6939SJiyong Park const struct memctl_opt *popts,
358*54fd6939SJiyong Park const struct dimm_params *pdimm)
359*54fd6939SJiyong Park {
360*54fd6939SJiyong Park const unsigned int freq = clk / 1000000U;
361*54fd6939SJiyong Park unsigned int rc0a, rc0f;
362*54fd6939SJiyong Park
363*54fd6939SJiyong Park if (pdimm->rdimm == 0) {
364*54fd6939SJiyong Park return;
365*54fd6939SJiyong Park }
366*54fd6939SJiyong Park
367*54fd6939SJiyong Park rc0a = freq > 3200U ? 7U :
368*54fd6939SJiyong Park (freq > 2933U ? 6U :
369*54fd6939SJiyong Park (freq > 2666U ? 5U :
370*54fd6939SJiyong Park (freq > 2400U ? 4U :
371*54fd6939SJiyong Park (freq > 2133U ? 3U :
372*54fd6939SJiyong Park (freq > 1866U ? 2U :
373*54fd6939SJiyong Park (freq > 1600U ? 1U : 0U))))));
374*54fd6939SJiyong Park rc0f = freq > 3200U ? 3U :
375*54fd6939SJiyong Park (freq > 2400U ? 2U :
376*54fd6939SJiyong Park (freq > 2133U ? 1U : 0U));
377*54fd6939SJiyong Park rc0f = (regs->sdram_cfg[1] & SDRAM_CFG2_AP_EN) ? rc0f : 4;
378*54fd6939SJiyong Park regs->sdram_rcw[0] =
379*54fd6939SJiyong Park pdimm->rcw[0] << 28 |
380*54fd6939SJiyong Park pdimm->rcw[1] << 24 |
381*54fd6939SJiyong Park pdimm->rcw[2] << 20 |
382*54fd6939SJiyong Park pdimm->rcw[3] << 16 |
383*54fd6939SJiyong Park pdimm->rcw[4] << 12 |
384*54fd6939SJiyong Park pdimm->rcw[5] << 8 |
385*54fd6939SJiyong Park pdimm->rcw[6] << 4 |
386*54fd6939SJiyong Park pdimm->rcw[7];
387*54fd6939SJiyong Park regs->sdram_rcw[1] =
388*54fd6939SJiyong Park pdimm->rcw[8] << 28 |
389*54fd6939SJiyong Park pdimm->rcw[9] << 24 |
390*54fd6939SJiyong Park rc0a << 20 |
391*54fd6939SJiyong Park pdimm->rcw[11] << 16 |
392*54fd6939SJiyong Park pdimm->rcw[12] << 12 |
393*54fd6939SJiyong Park pdimm->rcw[13] << 8 |
394*54fd6939SJiyong Park pdimm->rcw[14] << 4 |
395*54fd6939SJiyong Park rc0f;
396*54fd6939SJiyong Park regs->sdram_rcw[2] =
397*54fd6939SJiyong Park ((freq - 1260 + 19) / 20) << 8;
398*54fd6939SJiyong Park
399*54fd6939SJiyong Park debug("sdram_rcw[0] = 0x%x\n", regs->sdram_rcw[0]);
400*54fd6939SJiyong Park debug("sdram_rcw[1] = 0x%x\n", regs->sdram_rcw[1]);
401*54fd6939SJiyong Park debug("sdram_rcw[2] = 0x%x\n", regs->sdram_rcw[2]);
402*54fd6939SJiyong Park }
403*54fd6939SJiyong Park
cal_ddr_sdram_cfg(const unsigned long clk,struct ddr_cfg_regs * regs,const struct memctl_opt * popts,const struct dimm_params * pdimm,const unsigned int ip_rev)404*54fd6939SJiyong Park static void cal_ddr_sdram_cfg(const unsigned long clk,
405*54fd6939SJiyong Park struct ddr_cfg_regs *regs,
406*54fd6939SJiyong Park const struct memctl_opt *popts,
407*54fd6939SJiyong Park const struct dimm_params *pdimm,
408*54fd6939SJiyong Park const unsigned int ip_rev)
409*54fd6939SJiyong Park {
410*54fd6939SJiyong Park const unsigned int mem_en = 1U;
411*54fd6939SJiyong Park const unsigned int sren = popts->self_refresh_in_sleep;
412*54fd6939SJiyong Park const unsigned int ecc_en = popts->ecc_mode;
413*54fd6939SJiyong Park const unsigned int rd_en = (pdimm->rdimm != 0U) ? 1U : 0U;
414*54fd6939SJiyong Park const unsigned int dyn_pwr = popts->dynamic_power;
415*54fd6939SJiyong Park const unsigned int dbw = popts->data_bus_used;
416*54fd6939SJiyong Park const unsigned int eight_be = (dbw == 1U ||
417*54fd6939SJiyong Park popts->burst_length == DDR_BL8) ? 1U : 0U;
418*54fd6939SJiyong Park const unsigned int ncap = 0U;
419*54fd6939SJiyong Park const unsigned int threet_en = popts->threet_en;
420*54fd6939SJiyong Park const unsigned int twot_en = pdimm->rdimm ?
421*54fd6939SJiyong Park 0U : popts->twot_en;
422*54fd6939SJiyong Park const unsigned int ba_intlv = popts->ba_intlv;
423*54fd6939SJiyong Park const unsigned int x32_en = 0U;
424*54fd6939SJiyong Park const unsigned int pchb8 = 0U;
425*54fd6939SJiyong Park const unsigned int hse = popts->half_strength_drive_en;
426*54fd6939SJiyong Park const unsigned int acc_ecc_en = (dbw != 0U && ecc_en == 1U) ? 1U : 0U;
427*54fd6939SJiyong Park const unsigned int mem_halt = 0U;
428*54fd6939SJiyong Park #ifdef PHY_GEN2
429*54fd6939SJiyong Park const unsigned int bi = 1U;
430*54fd6939SJiyong Park #else
431*54fd6939SJiyong Park const unsigned int bi = 0U;
432*54fd6939SJiyong Park #endif
433*54fd6939SJiyong Park const unsigned int sdram_type = SDRAM_TYPE_DDR4;
434*54fd6939SJiyong Park unsigned int odt_cfg = 0U;
435*54fd6939SJiyong Park const unsigned int frc_sr = 0U;
436*54fd6939SJiyong Park const unsigned int sr_ie = popts->self_refresh_irq_en;
437*54fd6939SJiyong Park const unsigned int num_pr = pdimm->package_3ds + 1U;
438*54fd6939SJiyong Park const unsigned int slow = (clk < 1249000000U) ? 1U : 0U;
439*54fd6939SJiyong Park const unsigned int x4_en = popts->x4_en;
440*54fd6939SJiyong Park const unsigned int obc_cfg = popts->otf_burst_chop_en;
441*54fd6939SJiyong Park const unsigned int ap_en = ip_rev == 0x50500U ? 0U : popts->ap_en;
442*54fd6939SJiyong Park const unsigned int d_init = popts->ctlr_init_ecc;
443*54fd6939SJiyong Park const unsigned int rcw_en = popts->rdimm;
444*54fd6939SJiyong Park const unsigned int md_en = popts->mirrored_dimm;
445*54fd6939SJiyong Park const unsigned int qd_en = popts->quad_rank_present;
446*54fd6939SJiyong Park const unsigned int unq_mrs_en = ip_rev < 0x50500U ? 1U : 0U;
447*54fd6939SJiyong Park const unsigned int rd_pre = popts->quad_rank_present;
448*54fd6939SJiyong Park int i;
449*54fd6939SJiyong Park
450*54fd6939SJiyong Park regs->sdram_cfg[0] = ((mem_en & 0x1) << 31) |
451*54fd6939SJiyong Park ((sren & 0x1) << 30) |
452*54fd6939SJiyong Park ((ecc_en & 0x1) << 29) |
453*54fd6939SJiyong Park ((rd_en & 0x1) << 28) |
454*54fd6939SJiyong Park ((sdram_type & 0x7) << 24) |
455*54fd6939SJiyong Park ((dyn_pwr & 0x1) << 21) |
456*54fd6939SJiyong Park ((dbw & 0x3) << 19) |
457*54fd6939SJiyong Park ((eight_be & 0x1) << 18) |
458*54fd6939SJiyong Park ((ncap & 0x1) << 17) |
459*54fd6939SJiyong Park ((threet_en & 0x1) << 16) |
460*54fd6939SJiyong Park ((twot_en & 0x1) << 15) |
461*54fd6939SJiyong Park ((ba_intlv & 0x7F) << 8) |
462*54fd6939SJiyong Park ((x32_en & 0x1) << 5) |
463*54fd6939SJiyong Park ((pchb8 & 0x1) << 4) |
464*54fd6939SJiyong Park ((hse & 0x1) << 3) |
465*54fd6939SJiyong Park ((acc_ecc_en & 0x1) << 2) |
466*54fd6939SJiyong Park ((mem_halt & 0x1) << 1) |
467*54fd6939SJiyong Park ((bi & 0x1) << 0);
468*54fd6939SJiyong Park debug("sdram_cfg[0] = 0x%x\n", regs->sdram_cfg[0]);
469*54fd6939SJiyong Park
470*54fd6939SJiyong Park for (i = 0; i < DDRC_NUM_CS; i++) {
471*54fd6939SJiyong Park if (popts->cs_odt[i].odt_rd_cfg != 0 ||
472*54fd6939SJiyong Park popts->cs_odt[i].odt_wr_cfg != 0) {
473*54fd6939SJiyong Park odt_cfg = SDRAM_CFG2_ODT_ONLY_READ;
474*54fd6939SJiyong Park break;
475*54fd6939SJiyong Park }
476*54fd6939SJiyong Park }
477*54fd6939SJiyong Park
478*54fd6939SJiyong Park regs->sdram_cfg[1] = (0
479*54fd6939SJiyong Park | ((frc_sr & 0x1) << 31)
480*54fd6939SJiyong Park | ((sr_ie & 0x1) << 30)
481*54fd6939SJiyong Park | ((odt_cfg & 0x3) << 21)
482*54fd6939SJiyong Park | ((num_pr & 0xf) << 12)
483*54fd6939SJiyong Park | ((slow & 1) << 11)
484*54fd6939SJiyong Park | (x4_en << 10)
485*54fd6939SJiyong Park | (qd_en << 9)
486*54fd6939SJiyong Park | (unq_mrs_en << 8)
487*54fd6939SJiyong Park | ((obc_cfg & 0x1) << 6)
488*54fd6939SJiyong Park | ((ap_en & 0x1) << 5)
489*54fd6939SJiyong Park | ((d_init & 0x1) << 4)
490*54fd6939SJiyong Park | ((rcw_en & 0x1) << 2)
491*54fd6939SJiyong Park | ((md_en & 0x1) << 0)
492*54fd6939SJiyong Park );
493*54fd6939SJiyong Park debug("sdram_cfg[1] = 0x%x\n", regs->sdram_cfg[1]);
494*54fd6939SJiyong Park
495*54fd6939SJiyong Park regs->sdram_cfg[2] = (rd_pre & 0x1) << 16 |
496*54fd6939SJiyong Park (popts->rdimm ? 1 : 0);
497*54fd6939SJiyong Park if (pdimm->package_3ds != 0) {
498*54fd6939SJiyong Park if (((pdimm->package_3ds + 1) & 0x1) != 0) {
499*54fd6939SJiyong Park WARN("Unsupported 3DS DIMM\n");
500*54fd6939SJiyong Park } else {
501*54fd6939SJiyong Park regs->sdram_cfg[2] |= ((pdimm->package_3ds + 1) >> 1)
502*54fd6939SJiyong Park << 4;
503*54fd6939SJiyong Park }
504*54fd6939SJiyong Park }
505*54fd6939SJiyong Park debug("sdram_cfg[2] = 0x%x\n", regs->sdram_cfg[2]);
506*54fd6939SJiyong Park }
507*54fd6939SJiyong Park
508*54fd6939SJiyong Park
cal_ddr_sdram_interval(const unsigned long clk,struct ddr_cfg_regs * regs,const struct memctl_opt * popts,const struct dimm_params * pdimm)509*54fd6939SJiyong Park static void cal_ddr_sdram_interval(const unsigned long clk,
510*54fd6939SJiyong Park struct ddr_cfg_regs *regs,
511*54fd6939SJiyong Park const struct memctl_opt *popts,
512*54fd6939SJiyong Park const struct dimm_params *pdimm)
513*54fd6939SJiyong Park {
514*54fd6939SJiyong Park const unsigned int refint = picos_to_mclk(clk, pdimm->refresh_rate_ps);
515*54fd6939SJiyong Park const unsigned int bstopre = popts->bstopre;
516*54fd6939SJiyong Park
517*54fd6939SJiyong Park regs->interval = ((refint & 0xFFFF) << 16) |
518*54fd6939SJiyong Park ((bstopre & 0x3FFF) << 0);
519*54fd6939SJiyong Park debug("interval = 0x%x\n", regs->interval);
520*54fd6939SJiyong Park }
521*54fd6939SJiyong Park
522*54fd6939SJiyong Park /* Require cs and cfg first */
cal_ddr_sdram_mode(const unsigned long clk,struct ddr_cfg_regs * regs,const struct memctl_opt * popts,const struct ddr_conf * conf,const struct dimm_params * pdimm,unsigned int cas_latency,unsigned int additive_latency,const unsigned int ip_rev)523*54fd6939SJiyong Park static void cal_ddr_sdram_mode(const unsigned long clk,
524*54fd6939SJiyong Park struct ddr_cfg_regs *regs,
525*54fd6939SJiyong Park const struct memctl_opt *popts,
526*54fd6939SJiyong Park const struct ddr_conf *conf,
527*54fd6939SJiyong Park const struct dimm_params *pdimm,
528*54fd6939SJiyong Park unsigned int cas_latency,
529*54fd6939SJiyong Park unsigned int additive_latency,
530*54fd6939SJiyong Park const unsigned int ip_rev)
531*54fd6939SJiyong Park {
532*54fd6939SJiyong Park int i;
533*54fd6939SJiyong Park unsigned short esdmode; /* Extended SDRAM mode */
534*54fd6939SJiyong Park unsigned short sdmode; /* SDRAM mode */
535*54fd6939SJiyong Park
536*54fd6939SJiyong Park /* Mode Register - MR1 */
537*54fd6939SJiyong Park const unsigned int qoff = 0;
538*54fd6939SJiyong Park const unsigned int tdqs_en = 0;
539*54fd6939SJiyong Park unsigned int rtt;
540*54fd6939SJiyong Park const unsigned int wrlvl_en = 0;
541*54fd6939SJiyong Park unsigned int al = 0;
542*54fd6939SJiyong Park unsigned int dic = 0;
543*54fd6939SJiyong Park const unsigned int dll_en = 1;
544*54fd6939SJiyong Park
545*54fd6939SJiyong Park /* Mode Register - MR0 */
546*54fd6939SJiyong Park unsigned int wr = 0;
547*54fd6939SJiyong Park const unsigned int dll_rst = 0;
548*54fd6939SJiyong Park const unsigned int mode = 0;
549*54fd6939SJiyong Park unsigned int caslat = 4;/* CAS# latency, default set as 6 cycles */
550*54fd6939SJiyong Park /* BT: Burst Type (0=Nibble Sequential, 1=Interleaved) */
551*54fd6939SJiyong Park const unsigned int bt = 0;
552*54fd6939SJiyong Park const unsigned int bl = popts->burst_length == DDR_BL8 ? 0 :
553*54fd6939SJiyong Park (popts->burst_length == DDR_BC4 ? 2 : 1);
554*54fd6939SJiyong Park
555*54fd6939SJiyong Park const unsigned int wr_mclk = picos_to_mclk(clk, pdimm->twr_ps);
556*54fd6939SJiyong Park /* DDR4 support WR 10, 12, 14, 16, 18, 20, 24 */
557*54fd6939SJiyong Park static const int wr_table[] = {
558*54fd6939SJiyong Park 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6
559*54fd6939SJiyong Park };
560*54fd6939SJiyong Park /* DDR4 support CAS 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24 */
561*54fd6939SJiyong Park static const int cas_latency_table[] = {
562*54fd6939SJiyong Park 0, 1, 2, 3, 4, 5, 6, 7, 13, 8,
563*54fd6939SJiyong Park 14, 9, 15, 10, 12, 11, 16, 17,
564*54fd6939SJiyong Park 18, 19, 20, 21, 22, 23
565*54fd6939SJiyong Park };
566*54fd6939SJiyong Park const unsigned int unq_mrs_en = ip_rev < U(0x50500) ? 1U : 0U;
567*54fd6939SJiyong Park unsigned short esdmode2 = 0U;
568*54fd6939SJiyong Park unsigned short esdmode3 = 0U;
569*54fd6939SJiyong Park const unsigned int wr_crc = 0U;
570*54fd6939SJiyong Park unsigned int rtt_wr = 0U;
571*54fd6939SJiyong Park const unsigned int srt = 0U;
572*54fd6939SJiyong Park unsigned int cwl = cal_cwl(clk);
573*54fd6939SJiyong Park const unsigned int mpr = 0U;
574*54fd6939SJiyong Park const unsigned int mclk_ps = get_memory_clk_ps(clk);
575*54fd6939SJiyong Park const unsigned int wc_lat = 0U;
576*54fd6939SJiyong Park unsigned short esdmode4 = 0U;
577*54fd6939SJiyong Park unsigned short esdmode5;
578*54fd6939SJiyong Park int rtt_park_all = 0;
579*54fd6939SJiyong Park unsigned int rtt_park;
580*54fd6939SJiyong Park const bool four_cs = conf->cs_in_use == 0xf ? true : false;
581*54fd6939SJiyong Park unsigned short esdmode6 = 0U; /* Extended SDRAM mode 6 */
582*54fd6939SJiyong Park unsigned short esdmode7 = 0U; /* Extended SDRAM mode 7 */
583*54fd6939SJiyong Park const unsigned int tccdl_min = max(5U,
584*54fd6939SJiyong Park picos_to_mclk(clk, pdimm->tccdl_ps));
585*54fd6939SJiyong Park
586*54fd6939SJiyong Park if (popts->rtt_override != 0U) {
587*54fd6939SJiyong Park rtt = popts->rtt_override_value;
588*54fd6939SJiyong Park } else {
589*54fd6939SJiyong Park rtt = popts->cs_odt[0].odt_rtt_norm;
590*54fd6939SJiyong Park }
591*54fd6939SJiyong Park
592*54fd6939SJiyong Park if (additive_latency == (cas_latency - 1)) {
593*54fd6939SJiyong Park al = 1;
594*54fd6939SJiyong Park }
595*54fd6939SJiyong Park if (additive_latency == (cas_latency - 2)) {
596*54fd6939SJiyong Park al = 2;
597*54fd6939SJiyong Park }
598*54fd6939SJiyong Park
599*54fd6939SJiyong Park if (popts->quad_rank_present != 0 || popts->output_driver_impedance != 0) {
600*54fd6939SJiyong Park dic = 1; /* output driver impedance 240/7 ohm */
601*54fd6939SJiyong Park }
602*54fd6939SJiyong Park
603*54fd6939SJiyong Park esdmode = (((qoff & 0x1) << 12) |
604*54fd6939SJiyong Park ((tdqs_en & 0x1) << 11) |
605*54fd6939SJiyong Park ((rtt & 0x7) << 8) |
606*54fd6939SJiyong Park ((wrlvl_en & 0x1) << 7) |
607*54fd6939SJiyong Park ((al & 0x3) << 3) |
608*54fd6939SJiyong Park ((dic & 0x3) << 1) |
609*54fd6939SJiyong Park ((dll_en & 0x1) << 0));
610*54fd6939SJiyong Park
611*54fd6939SJiyong Park if (wr_mclk >= 10 && wr_mclk <= 24) {
612*54fd6939SJiyong Park wr = wr_table[wr_mclk - 10];
613*54fd6939SJiyong Park } else {
614*54fd6939SJiyong Park ERROR("unsupported wc_mclk = %d for mode register\n", wr_mclk);
615*54fd6939SJiyong Park }
616*54fd6939SJiyong Park
617*54fd6939SJiyong Park /* look up table to get the cas latency bits */
618*54fd6939SJiyong Park if (cas_latency >= 9 && cas_latency <= 32) {
619*54fd6939SJiyong Park caslat = cas_latency_table[cas_latency - 9];
620*54fd6939SJiyong Park } else {
621*54fd6939SJiyong Park WARN("Error: unsupported cas latency for mode register\n");
622*54fd6939SJiyong Park }
623*54fd6939SJiyong Park
624*54fd6939SJiyong Park sdmode = (((caslat & 0x10) << 8) |
625*54fd6939SJiyong Park ((wr & 0x7) << 9) |
626*54fd6939SJiyong Park ((dll_rst & 0x1) << 8) |
627*54fd6939SJiyong Park ((mode & 0x1) << 7) |
628*54fd6939SJiyong Park (((caslat >> 1) & 0x7) << 4) |
629*54fd6939SJiyong Park ((bt & 0x1) << 3) |
630*54fd6939SJiyong Park ((caslat & 1) << 2) |
631*54fd6939SJiyong Park ((bl & 0x3) << 0));
632*54fd6939SJiyong Park
633*54fd6939SJiyong Park regs->sdram_mode[0] = (((esdmode & 0xFFFF) << 16) |
634*54fd6939SJiyong Park ((sdmode & 0xFFFF) << 0));
635*54fd6939SJiyong Park debug("sdram_mode[0] = 0x%x\n", regs->sdram_mode[0]);
636*54fd6939SJiyong Park
637*54fd6939SJiyong Park switch (cwl) {
638*54fd6939SJiyong Park case 9:
639*54fd6939SJiyong Park case 10:
640*54fd6939SJiyong Park case 11:
641*54fd6939SJiyong Park case 12:
642*54fd6939SJiyong Park cwl -= 9;
643*54fd6939SJiyong Park break;
644*54fd6939SJiyong Park case 14:
645*54fd6939SJiyong Park cwl -= 10;
646*54fd6939SJiyong Park break;
647*54fd6939SJiyong Park case 16:
648*54fd6939SJiyong Park cwl -= 11;
649*54fd6939SJiyong Park break;
650*54fd6939SJiyong Park case 18:
651*54fd6939SJiyong Park cwl -= 12;
652*54fd6939SJiyong Park break;
653*54fd6939SJiyong Park case 20:
654*54fd6939SJiyong Park cwl -= 13;
655*54fd6939SJiyong Park break;
656*54fd6939SJiyong Park default:
657*54fd6939SJiyong Park printf("Error CWL\n");
658*54fd6939SJiyong Park break;
659*54fd6939SJiyong Park }
660*54fd6939SJiyong Park
661*54fd6939SJiyong Park if (popts->rtt_override != 0) {
662*54fd6939SJiyong Park rtt_wr = popts->rtt_wr_override_value;
663*54fd6939SJiyong Park } else {
664*54fd6939SJiyong Park rtt_wr = popts->cs_odt[0].odt_rtt_wr;
665*54fd6939SJiyong Park }
666*54fd6939SJiyong Park
667*54fd6939SJiyong Park esdmode2 = ((wr_crc & 0x1) << 12) |
668*54fd6939SJiyong Park ((rtt_wr & 0x7) << 9) |
669*54fd6939SJiyong Park ((srt & 0x3) << 6) |
670*54fd6939SJiyong Park ((cwl & 0x7) << 3);
671*54fd6939SJiyong Park esdmode3 = ((mpr & 0x3) << 11) | ((wc_lat & 0x3) << 9);
672*54fd6939SJiyong Park
673*54fd6939SJiyong Park regs->sdram_mode[1] = ((esdmode2 & 0xFFFF) << 16) |
674*54fd6939SJiyong Park ((esdmode3 & 0xFFFF) << 0);
675*54fd6939SJiyong Park debug("sdram_mode[1] = 0x%x\n", regs->sdram_mode[1]);
676*54fd6939SJiyong Park
677*54fd6939SJiyong Park esdmode6 = ((tccdl_min - 4) & 0x7) << 10;
678*54fd6939SJiyong Park if (popts->vref_dimm != 0) {
679*54fd6939SJiyong Park esdmode6 |= popts->vref_dimm & 0x7f;
680*54fd6939SJiyong Park } else if ((popts->ddr_cdr2 & DDR_CDR2_VREF_RANGE_2) != 0) {
681*54fd6939SJiyong Park esdmode6 |= 1 << 6; /* Range 2 */
682*54fd6939SJiyong Park }
683*54fd6939SJiyong Park
684*54fd6939SJiyong Park regs->sdram_mode[9] = ((esdmode6 & 0xffff) << 16) |
685*54fd6939SJiyong Park ((esdmode7 & 0xffff) << 0);
686*54fd6939SJiyong Park debug("sdram_mode[9] = 0x%x\n", regs->sdram_mode[9]);
687*54fd6939SJiyong Park
688*54fd6939SJiyong Park rtt_park = (popts->rtt_park != 0) ? popts->rtt_park : 240;
689*54fd6939SJiyong Park switch (rtt_park) {
690*54fd6939SJiyong Park case 240:
691*54fd6939SJiyong Park rtt_park = 0x4;
692*54fd6939SJiyong Park break;
693*54fd6939SJiyong Park case 120:
694*54fd6939SJiyong Park rtt_park = 0x2;
695*54fd6939SJiyong Park break;
696*54fd6939SJiyong Park case 80:
697*54fd6939SJiyong Park rtt_park = 0x6;
698*54fd6939SJiyong Park break;
699*54fd6939SJiyong Park case 60:
700*54fd6939SJiyong Park rtt_park = 0x1;
701*54fd6939SJiyong Park break;
702*54fd6939SJiyong Park case 48:
703*54fd6939SJiyong Park rtt_park = 0x5;
704*54fd6939SJiyong Park break;
705*54fd6939SJiyong Park case 40:
706*54fd6939SJiyong Park rtt_park = 0x3;
707*54fd6939SJiyong Park break;
708*54fd6939SJiyong Park case 34:
709*54fd6939SJiyong Park rtt_park = 0x7;
710*54fd6939SJiyong Park break;
711*54fd6939SJiyong Park default:
712*54fd6939SJiyong Park rtt_park = 0;
713*54fd6939SJiyong Park break;
714*54fd6939SJiyong Park }
715*54fd6939SJiyong Park
716*54fd6939SJiyong Park for (i = 0; i < DDRC_NUM_CS; i++) {
717*54fd6939SJiyong Park if (i != 0 && unq_mrs_en == 0) {
718*54fd6939SJiyong Park break;
719*54fd6939SJiyong Park }
720*54fd6939SJiyong Park
721*54fd6939SJiyong Park if (popts->rtt_override != 0) {
722*54fd6939SJiyong Park rtt = popts->rtt_override_value;
723*54fd6939SJiyong Park rtt_wr = popts->rtt_wr_override_value;
724*54fd6939SJiyong Park } else {
725*54fd6939SJiyong Park rtt = popts->cs_odt[i].odt_rtt_norm;
726*54fd6939SJiyong Park rtt_wr = popts->cs_odt[i].odt_rtt_wr;
727*54fd6939SJiyong Park }
728*54fd6939SJiyong Park
729*54fd6939SJiyong Park esdmode &= 0xF8FF; /* clear bit 10,9,8 for rtt */
730*54fd6939SJiyong Park esdmode |= (rtt & 0x7) << 8;
731*54fd6939SJiyong Park esdmode2 &= 0xF9FF; /* clear bit 10, 9 */
732*54fd6939SJiyong Park esdmode2 |= (rtt_wr & 0x3) << 9;
733*54fd6939SJiyong Park esdmode5 = (popts->x4_en) ? 0 : 0x400; /* data mask */
734*54fd6939SJiyong Park
735*54fd6939SJiyong Park if (rtt_park_all == 0 &&
736*54fd6939SJiyong Park ((regs->cs[i].config & SDRAM_CS_CONFIG_EN) != 0)) {
737*54fd6939SJiyong Park esdmode5 |= rtt_park << 6;
738*54fd6939SJiyong Park rtt_park_all = four_cs ? 0 : 1;
739*54fd6939SJiyong Park }
740*54fd6939SJiyong Park
741*54fd6939SJiyong Park if (((regs->sdram_cfg[1] & SDRAM_CFG2_AP_EN) != 0) &&
742*54fd6939SJiyong Park (popts->rdimm == 0)) {
743*54fd6939SJiyong Park if (mclk_ps >= 935) {
744*54fd6939SJiyong Park esdmode5 |= DDR_MR5_CA_PARITY_LAT_4_CLK;
745*54fd6939SJiyong Park } else if (mclk_ps >= 833) {
746*54fd6939SJiyong Park esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
747*54fd6939SJiyong Park } else {
748*54fd6939SJiyong Park esdmode5 |= DDR_MR5_CA_PARITY_LAT_5_CLK;
749*54fd6939SJiyong Park WARN("mclk_ps not supported %d", mclk_ps);
750*54fd6939SJiyong Park
751*54fd6939SJiyong Park }
752*54fd6939SJiyong Park }
753*54fd6939SJiyong Park
754*54fd6939SJiyong Park switch (i) {
755*54fd6939SJiyong Park case 0:
756*54fd6939SJiyong Park regs->sdram_mode[8] = ((esdmode4 & 0xffff) << 16) |
757*54fd6939SJiyong Park ((esdmode5 & 0xffff) << 0);
758*54fd6939SJiyong Park debug("sdram_mode[8] = 0x%x\n", regs->sdram_mode[8]);
759*54fd6939SJiyong Park break;
760*54fd6939SJiyong Park case 1:
761*54fd6939SJiyong Park regs->sdram_mode[2] = (((esdmode & 0xFFFF) << 16) |
762*54fd6939SJiyong Park ((sdmode & 0xFFFF) << 0));
763*54fd6939SJiyong Park regs->sdram_mode[3] = ((esdmode2 & 0xFFFF) << 16) |
764*54fd6939SJiyong Park ((esdmode3 & 0xFFFF) << 0);
765*54fd6939SJiyong Park regs->sdram_mode[10] = ((esdmode4 & 0xFFFF) << 16) |
766*54fd6939SJiyong Park ((esdmode5 & 0xFFFF) << 0);
767*54fd6939SJiyong Park regs->sdram_mode[11] = ((esdmode6 & 0xFFFF) << 16) |
768*54fd6939SJiyong Park ((esdmode7 & 0xFFFF) << 0);
769*54fd6939SJiyong Park debug("sdram_mode[2] = 0x%x\n", regs->sdram_mode[2]);
770*54fd6939SJiyong Park debug("sdram_mode[3] = 0x%x\n", regs->sdram_mode[3]);
771*54fd6939SJiyong Park debug("sdram_mode[10] = 0x%x\n", regs->sdram_mode[10]);
772*54fd6939SJiyong Park debug("sdram_mode[11] = 0x%x\n", regs->sdram_mode[11]);
773*54fd6939SJiyong Park break;
774*54fd6939SJiyong Park case 2:
775*54fd6939SJiyong Park regs->sdram_mode[4] = (((esdmode & 0xFFFF) << 16) |
776*54fd6939SJiyong Park ((sdmode & 0xFFFF) << 0));
777*54fd6939SJiyong Park regs->sdram_mode[5] = ((esdmode2 & 0xFFFF) << 16) |
778*54fd6939SJiyong Park ((esdmode3 & 0xFFFF) << 0);
779*54fd6939SJiyong Park regs->sdram_mode[12] = ((esdmode4 & 0xFFFF) << 16) |
780*54fd6939SJiyong Park ((esdmode5 & 0xFFFF) << 0);
781*54fd6939SJiyong Park regs->sdram_mode[13] = ((esdmode6 & 0xFFFF) << 16) |
782*54fd6939SJiyong Park ((esdmode7 & 0xFFFF) << 0);
783*54fd6939SJiyong Park debug("sdram_mode[4] = 0x%x\n", regs->sdram_mode[4]);
784*54fd6939SJiyong Park debug("sdram_mode[5] = 0x%x\n", regs->sdram_mode[5]);
785*54fd6939SJiyong Park debug("sdram_mode[12] = 0x%x\n", regs->sdram_mode[12]);
786*54fd6939SJiyong Park debug("sdram_mode[13] = 0x%x\n", regs->sdram_mode[13]);
787*54fd6939SJiyong Park break;
788*54fd6939SJiyong Park case 3:
789*54fd6939SJiyong Park regs->sdram_mode[6] = (((esdmode & 0xFFFF) << 16) |
790*54fd6939SJiyong Park ((sdmode & 0xFFFF) << 0));
791*54fd6939SJiyong Park regs->sdram_mode[7] = ((esdmode2 & 0xFFFF) << 16) |
792*54fd6939SJiyong Park ((esdmode3 & 0xFFFF) << 0);
793*54fd6939SJiyong Park regs->sdram_mode[14] = ((esdmode4 & 0xFFFF) << 16) |
794*54fd6939SJiyong Park ((esdmode5 & 0xFFFF) << 0);
795*54fd6939SJiyong Park regs->sdram_mode[15] = ((esdmode6 & 0xFFFF) << 16) |
796*54fd6939SJiyong Park ((esdmode7 & 0xFFFF) << 0);
797*54fd6939SJiyong Park debug("sdram_mode[6] = 0x%x\n", regs->sdram_mode[6]);
798*54fd6939SJiyong Park debug("sdram_mode[7] = 0x%x\n", regs->sdram_mode[7]);
799*54fd6939SJiyong Park debug("sdram_mode[14] = 0x%x\n", regs->sdram_mode[14]);
800*54fd6939SJiyong Park debug("sdram_mode[15] = 0x%x\n", regs->sdram_mode[15]);
801*54fd6939SJiyong Park break;
802*54fd6939SJiyong Park default:
803*54fd6939SJiyong Park break;
804*54fd6939SJiyong Park }
805*54fd6939SJiyong Park }
806*54fd6939SJiyong Park }
807*54fd6939SJiyong Park
808*54fd6939SJiyong Park #ifndef CONFIG_MEM_INIT_VALUE
809*54fd6939SJiyong Park #define CONFIG_MEM_INIT_VALUE 0xDEADBEEF
810*54fd6939SJiyong Park #endif
cal_ddr_data_init(struct ddr_cfg_regs * regs)811*54fd6939SJiyong Park static void cal_ddr_data_init(struct ddr_cfg_regs *regs)
812*54fd6939SJiyong Park {
813*54fd6939SJiyong Park regs->data_init = CONFIG_MEM_INIT_VALUE;
814*54fd6939SJiyong Park }
815*54fd6939SJiyong Park
cal_ddr_dq_mapping(struct ddr_cfg_regs * regs,const struct dimm_params * pdimm)816*54fd6939SJiyong Park static void cal_ddr_dq_mapping(struct ddr_cfg_regs *regs,
817*54fd6939SJiyong Park const struct dimm_params *pdimm)
818*54fd6939SJiyong Park {
819*54fd6939SJiyong Park const unsigned int acc_ecc_en = (regs->sdram_cfg[0] >> 2) & 0x1;
820*54fd6939SJiyong Park /* FIXME: revert the dq mapping from DIMM */
821*54fd6939SJiyong Park regs->dq_map[0] = ((pdimm->dq_mapping[0] & 0x3F) << 26) |
822*54fd6939SJiyong Park ((pdimm->dq_mapping[1] & 0x3F) << 20) |
823*54fd6939SJiyong Park ((pdimm->dq_mapping[2] & 0x3F) << 14) |
824*54fd6939SJiyong Park ((pdimm->dq_mapping[3] & 0x3F) << 8) |
825*54fd6939SJiyong Park ((pdimm->dq_mapping[4] & 0x3F) << 2);
826*54fd6939SJiyong Park
827*54fd6939SJiyong Park regs->dq_map[1] = ((pdimm->dq_mapping[5] & 0x3F) << 26) |
828*54fd6939SJiyong Park ((pdimm->dq_mapping[6] & 0x3F) << 20) |
829*54fd6939SJiyong Park ((pdimm->dq_mapping[7] & 0x3F) << 14) |
830*54fd6939SJiyong Park ((pdimm->dq_mapping[10] & 0x3F) << 8) |
831*54fd6939SJiyong Park ((pdimm->dq_mapping[11] & 0x3F) << 2);
832*54fd6939SJiyong Park
833*54fd6939SJiyong Park regs->dq_map[2] = ((pdimm->dq_mapping[12] & 0x3F) << 26) |
834*54fd6939SJiyong Park ((pdimm->dq_mapping[13] & 0x3F) << 20) |
835*54fd6939SJiyong Park ((pdimm->dq_mapping[14] & 0x3F) << 14) |
836*54fd6939SJiyong Park ((pdimm->dq_mapping[15] & 0x3F) << 8) |
837*54fd6939SJiyong Park ((pdimm->dq_mapping[16] & 0x3F) << 2);
838*54fd6939SJiyong Park
839*54fd6939SJiyong Park /* dq_map for ECC[4:7] is set to 0 if accumulated ECC is enabled */
840*54fd6939SJiyong Park regs->dq_map[3] = ((pdimm->dq_mapping[17] & 0x3F) << 26) |
841*54fd6939SJiyong Park ((pdimm->dq_mapping[8] & 0x3F) << 20) |
842*54fd6939SJiyong Park ((acc_ecc_en != 0) ? 0 :
843*54fd6939SJiyong Park (pdimm->dq_mapping[9] & 0x3F) << 14) |
844*54fd6939SJiyong Park pdimm->dq_mapping_ors;
845*54fd6939SJiyong Park debug("dq_map[0] = 0x%x\n", regs->dq_map[0]);
846*54fd6939SJiyong Park debug("dq_map[1] = 0x%x\n", regs->dq_map[1]);
847*54fd6939SJiyong Park debug("dq_map[2] = 0x%x\n", regs->dq_map[2]);
848*54fd6939SJiyong Park debug("dq_map[3] = 0x%x\n", regs->dq_map[3]);
849*54fd6939SJiyong Park }
cal_ddr_zq_cntl(struct ddr_cfg_regs * regs)850*54fd6939SJiyong Park static void cal_ddr_zq_cntl(struct ddr_cfg_regs *regs)
851*54fd6939SJiyong Park {
852*54fd6939SJiyong Park const unsigned int zqinit = 10U; /* 1024 clocks */
853*54fd6939SJiyong Park const unsigned int zqoper = 9U; /* 512 clocks */
854*54fd6939SJiyong Park const unsigned int zqcs = 7U; /* 128 clocks */
855*54fd6939SJiyong Park const unsigned int zqcs_init = 5U; /* 1024 refresh seqences */
856*54fd6939SJiyong Park const unsigned int zq_en = 1U; /* enabled */
857*54fd6939SJiyong Park
858*54fd6939SJiyong Park regs->zq_cntl = ((zq_en & 0x1) << 31) |
859*54fd6939SJiyong Park ((zqinit & 0xF) << 24) |
860*54fd6939SJiyong Park ((zqoper & 0xF) << 16) |
861*54fd6939SJiyong Park ((zqcs & 0xF) << 8) |
862*54fd6939SJiyong Park ((zqcs_init & 0xF) << 0);
863*54fd6939SJiyong Park debug("zq_cntl = 0x%x\n", regs->zq_cntl);
864*54fd6939SJiyong Park }
865*54fd6939SJiyong Park
cal_ddr_sr_cntr(struct ddr_cfg_regs * regs,const struct memctl_opt * popts)866*54fd6939SJiyong Park static void cal_ddr_sr_cntr(struct ddr_cfg_regs *regs,
867*54fd6939SJiyong Park const struct memctl_opt *popts)
868*54fd6939SJiyong Park {
869*54fd6939SJiyong Park const unsigned int sr_it = (popts->auto_self_refresh_en) ?
870*54fd6939SJiyong Park popts->sr_it : 0;
871*54fd6939SJiyong Park
872*54fd6939SJiyong Park regs->ddr_sr_cntr = (sr_it & 0xF) << 16;
873*54fd6939SJiyong Park debug("ddr_sr_cntr = 0x%x\n", regs->ddr_sr_cntr);
874*54fd6939SJiyong Park }
875*54fd6939SJiyong Park
cal_ddr_eor(struct ddr_cfg_regs * regs,const struct memctl_opt * popts)876*54fd6939SJiyong Park static void cal_ddr_eor(struct ddr_cfg_regs *regs,
877*54fd6939SJiyong Park const struct memctl_opt *popts)
878*54fd6939SJiyong Park {
879*54fd6939SJiyong Park if (popts->addr_hash != 0) {
880*54fd6939SJiyong Park regs->eor = 0x40000000; /* address hash enable */
881*54fd6939SJiyong Park debug("eor = 0x%x\n", regs->eor);
882*54fd6939SJiyong Park }
883*54fd6939SJiyong Park }
884*54fd6939SJiyong Park
cal_ddr_csn_bnds(struct ddr_cfg_regs * regs,const struct memctl_opt * popts,const struct ddr_conf * conf,const struct dimm_params * pdimm)885*54fd6939SJiyong Park static void cal_ddr_csn_bnds(struct ddr_cfg_regs *regs,
886*54fd6939SJiyong Park const struct memctl_opt *popts,
887*54fd6939SJiyong Park const struct ddr_conf *conf,
888*54fd6939SJiyong Park const struct dimm_params *pdimm)
889*54fd6939SJiyong Park {
890*54fd6939SJiyong Park int i;
891*54fd6939SJiyong Park unsigned long long ea, sa;
892*54fd6939SJiyong Park
893*54fd6939SJiyong Park /* Chip Select Memory Bounds (CSn_BNDS) */
894*54fd6939SJiyong Park for (i = 0;
895*54fd6939SJiyong Park i < DDRC_NUM_CS && conf->cs_size[i];
896*54fd6939SJiyong Park i++) {
897*54fd6939SJiyong Park debug("cs_in_use = 0x%x\n", conf->cs_in_use);
898*54fd6939SJiyong Park if (conf->cs_in_use != 0) {
899*54fd6939SJiyong Park sa = conf->cs_base_addr[i];
900*54fd6939SJiyong Park ea = sa + conf->cs_size[i] - 1;
901*54fd6939SJiyong Park sa >>= 24;
902*54fd6939SJiyong Park ea >>= 24;
903*54fd6939SJiyong Park regs->cs[i].bnds = ((sa & 0xffff) << 16) |
904*54fd6939SJiyong Park ((ea & 0xffff) << 0);
905*54fd6939SJiyong Park cal_csn_config(i, regs, popts, pdimm);
906*54fd6939SJiyong Park } else {
907*54fd6939SJiyong Park /* setting bnds to 0xffffffff for inactive CS */
908*54fd6939SJiyong Park regs->cs[i].bnds = 0xffffffff;
909*54fd6939SJiyong Park }
910*54fd6939SJiyong Park
911*54fd6939SJiyong Park debug("cs[%d].bnds = 0x%x\n", i, regs->cs[i].bnds);
912*54fd6939SJiyong Park }
913*54fd6939SJiyong Park }
914*54fd6939SJiyong Park
cal_ddr_addr_dec(struct ddr_cfg_regs * regs)915*54fd6939SJiyong Park static void cal_ddr_addr_dec(struct ddr_cfg_regs *regs)
916*54fd6939SJiyong Park {
917*54fd6939SJiyong Park #ifdef CONFIG_DDR_ADDR_DEC
918*54fd6939SJiyong Park unsigned int ba_bits __unused;
919*54fd6939SJiyong Park char p __unused;
920*54fd6939SJiyong Park const unsigned int cs0_config = regs->cs[0].config;
921*54fd6939SJiyong Park const int cacheline = PLATFORM_CACHE_LINE_SHIFT;
922*54fd6939SJiyong Park unsigned int bg_bits;
923*54fd6939SJiyong Park unsigned int row_bits;
924*54fd6939SJiyong Park unsigned int col_bits;
925*54fd6939SJiyong Park unsigned int cs;
926*54fd6939SJiyong Park unsigned int map_row[18];
927*54fd6939SJiyong Park unsigned int map_col[11];
928*54fd6939SJiyong Park unsigned int map_ba[2];
929*54fd6939SJiyong Park unsigned int map_cid[2] = {0x3F, 0x3F};
930*54fd6939SJiyong Park unsigned int map_bg[2] = {0x3F, 0x3F};
931*54fd6939SJiyong Park unsigned int map_cs[2] = {0x3F, 0x3F};
932*54fd6939SJiyong Park unsigned int dbw;
933*54fd6939SJiyong Park unsigned int ba_intlv;
934*54fd6939SJiyong Park int placement;
935*54fd6939SJiyong Park int intlv;
936*54fd6939SJiyong Park int abort = 0;
937*54fd6939SJiyong Park int i;
938*54fd6939SJiyong Park int j;
939*54fd6939SJiyong Park
940*54fd6939SJiyong Park col_bits = (cs0_config >> 0) & 0x7;
941*54fd6939SJiyong Park if (col_bits < 4) {
942*54fd6939SJiyong Park col_bits += 8;
943*54fd6939SJiyong Park } else if (col_bits < 7 || col_bits > 10) {
944*54fd6939SJiyong Park ERROR("Error %s col_bits = %d\n", __func__, col_bits);
945*54fd6939SJiyong Park }
946*54fd6939SJiyong Park row_bits = ((cs0_config >> 8) & 0x7) + 12;
947*54fd6939SJiyong Park ba_bits = ((cs0_config >> 14) & 0x3) + 2;
948*54fd6939SJiyong Park bg_bits = ((cs0_config >> 4) & 0x3) + 0;
949*54fd6939SJiyong Park intlv = (cs0_config >> 24) & 0xf;
950*54fd6939SJiyong Park ba_intlv = (regs->sdram_cfg[0] >> 8) & 0x7f;
951*54fd6939SJiyong Park switch (ba_intlv) {
952*54fd6939SJiyong Park case DDR_BA_INTLV_CS01:
953*54fd6939SJiyong Park cs = 1;
954*54fd6939SJiyong Park break;
955*54fd6939SJiyong Park case DDR_BA_INTLV_CS0123:
956*54fd6939SJiyong Park cs = 2;
957*54fd6939SJiyong Park break;
958*54fd6939SJiyong Park case DDR_BA_NONE:
959*54fd6939SJiyong Park cs = 0;
960*54fd6939SJiyong Park break;
961*54fd6939SJiyong Park default:
962*54fd6939SJiyong Park ERROR("%s ba_intlv 0x%x\n", __func__, ba_intlv);
963*54fd6939SJiyong Park return;
964*54fd6939SJiyong Park }
965*54fd6939SJiyong Park debug("col %d, row %d, ba %d, bg %d, intlv %d\n",
966*54fd6939SJiyong Park col_bits, row_bits, ba_bits, bg_bits, intlv);
967*54fd6939SJiyong Park /*
968*54fd6939SJiyong Park * Example mapping of 15x2x2x10
969*54fd6939SJiyong Park * ---- --rr rrrr rrrr rrrr rCBB Gccc cccI cGcc cbbb
970*54fd6939SJiyong Park */
971*54fd6939SJiyong Park dbw = (regs->sdram_cfg[0] >> 19) & 0x3;
972*54fd6939SJiyong Park switch (dbw) {
973*54fd6939SJiyong Park case 0: /* 64-bit */
974*54fd6939SJiyong Park placement = 3;
975*54fd6939SJiyong Park break;
976*54fd6939SJiyong Park case 1: /* 32-bit */
977*54fd6939SJiyong Park placement = 2;
978*54fd6939SJiyong Park break;
979*54fd6939SJiyong Park default:
980*54fd6939SJiyong Park ERROR("%s dbw = %d\n", __func__, dbw);
981*54fd6939SJiyong Park return;
982*54fd6939SJiyong Park }
983*54fd6939SJiyong Park debug("cacheline size %d\n", cacheline);
984*54fd6939SJiyong Park for (i = 0; placement < cacheline; i++) {
985*54fd6939SJiyong Park map_col[i] = placement++;
986*54fd6939SJiyong Park }
987*54fd6939SJiyong Park map_bg[0] = placement++;
988*54fd6939SJiyong Park for ( ; i < col_bits; i++) {
989*54fd6939SJiyong Park map_col[i] = placement++;
990*54fd6939SJiyong Park if (placement == intlv) {
991*54fd6939SJiyong Park placement++;
992*54fd6939SJiyong Park }
993*54fd6939SJiyong Park }
994*54fd6939SJiyong Park for ( ; i < 11; i++) {
995*54fd6939SJiyong Park map_col[i] = 0x3F; /* unused col bits */
996*54fd6939SJiyong Park }
997*54fd6939SJiyong Park
998*54fd6939SJiyong Park if (bg_bits >= 2) {
999*54fd6939SJiyong Park map_bg[1] = placement++;
1000*54fd6939SJiyong Park }
1001*54fd6939SJiyong Park map_ba[0] = placement++;
1002*54fd6939SJiyong Park map_ba[1] = placement++;
1003*54fd6939SJiyong Park if (cs != 0U) {
1004*54fd6939SJiyong Park map_cs[0] = placement++;
1005*54fd6939SJiyong Park if (cs == 2U) {
1006*54fd6939SJiyong Park map_cs[1] = placement++;
1007*54fd6939SJiyong Park }
1008*54fd6939SJiyong Park } else {
1009*54fd6939SJiyong Park map_cs[0] = U(0x3F);
1010*54fd6939SJiyong Park }
1011*54fd6939SJiyong Park
1012*54fd6939SJiyong Park for (i = 0; i < row_bits; i++) {
1013*54fd6939SJiyong Park map_row[i] = placement++;
1014*54fd6939SJiyong Park }
1015*54fd6939SJiyong Park
1016*54fd6939SJiyong Park for ( ; i < 18; i++) {
1017*54fd6939SJiyong Park map_row[i] = 0x3F; /* unused row bits */
1018*54fd6939SJiyong Park }
1019*54fd6939SJiyong Park
1020*54fd6939SJiyong Park for (i = 39; i >= 0 ; i--) {
1021*54fd6939SJiyong Park if (i == intlv) {
1022*54fd6939SJiyong Park placement = 8;
1023*54fd6939SJiyong Park p = 'I';
1024*54fd6939SJiyong Park } else if (i < 3) {
1025*54fd6939SJiyong Park p = 'b';
1026*54fd6939SJiyong Park placement = 0;
1027*54fd6939SJiyong Park } else {
1028*54fd6939SJiyong Park placement = 0;
1029*54fd6939SJiyong Park p = '-';
1030*54fd6939SJiyong Park }
1031*54fd6939SJiyong Park for (j = 0; j < 18; j++) {
1032*54fd6939SJiyong Park if (map_row[j] != i) {
1033*54fd6939SJiyong Park continue;
1034*54fd6939SJiyong Park }
1035*54fd6939SJiyong Park if (placement != 0) {
1036*54fd6939SJiyong Park abort = 1;
1037*54fd6939SJiyong Park ERROR("%s wrong address bit %d\n", __func__, i);
1038*54fd6939SJiyong Park }
1039*54fd6939SJiyong Park placement = i;
1040*54fd6939SJiyong Park p = 'r';
1041*54fd6939SJiyong Park }
1042*54fd6939SJiyong Park for (j = 0; j < 11; j++) {
1043*54fd6939SJiyong Park if (map_col[j] != i) {
1044*54fd6939SJiyong Park continue;
1045*54fd6939SJiyong Park }
1046*54fd6939SJiyong Park if (placement != 0) {
1047*54fd6939SJiyong Park abort = 1;
1048*54fd6939SJiyong Park ERROR("%s wrong address bit %d\n", __func__, i);
1049*54fd6939SJiyong Park }
1050*54fd6939SJiyong Park placement = i;
1051*54fd6939SJiyong Park p = 'c';
1052*54fd6939SJiyong Park }
1053*54fd6939SJiyong Park for (j = 0; j < 2; j++) {
1054*54fd6939SJiyong Park if (map_ba[j] != i) {
1055*54fd6939SJiyong Park continue;
1056*54fd6939SJiyong Park }
1057*54fd6939SJiyong Park if (placement != 0) {
1058*54fd6939SJiyong Park abort = 1;
1059*54fd6939SJiyong Park ERROR("%s wrong address bit %d\n", __func__, i);
1060*54fd6939SJiyong Park }
1061*54fd6939SJiyong Park placement = i;
1062*54fd6939SJiyong Park p = 'B';
1063*54fd6939SJiyong Park }
1064*54fd6939SJiyong Park for (j = 0; j < 2; j++) {
1065*54fd6939SJiyong Park if (map_bg[j] != i) {
1066*54fd6939SJiyong Park continue;
1067*54fd6939SJiyong Park }
1068*54fd6939SJiyong Park if (placement != 0) {
1069*54fd6939SJiyong Park abort = 1;
1070*54fd6939SJiyong Park ERROR("%s wrong address bit %d\n", __func__, i);
1071*54fd6939SJiyong Park }
1072*54fd6939SJiyong Park placement = i;
1073*54fd6939SJiyong Park p = 'G';
1074*54fd6939SJiyong Park }
1075*54fd6939SJiyong Park for (j = 0; j < 2; j++) {
1076*54fd6939SJiyong Park if (map_cs[j] != i) {
1077*54fd6939SJiyong Park continue;
1078*54fd6939SJiyong Park }
1079*54fd6939SJiyong Park if (placement != 0) {
1080*54fd6939SJiyong Park abort = 1;
1081*54fd6939SJiyong Park ERROR("%s wrong address bit %d\n", __func__, i);
1082*54fd6939SJiyong Park }
1083*54fd6939SJiyong Park placement = i;
1084*54fd6939SJiyong Park p = 'C';
1085*54fd6939SJiyong Park }
1086*54fd6939SJiyong Park #ifdef DDR_DEBUG
1087*54fd6939SJiyong Park printf("%c", p);
1088*54fd6939SJiyong Park if ((i % 4) == 0) {
1089*54fd6939SJiyong Park printf(" ");
1090*54fd6939SJiyong Park }
1091*54fd6939SJiyong Park #endif
1092*54fd6939SJiyong Park }
1093*54fd6939SJiyong Park #ifdef DDR_DEBUG
1094*54fd6939SJiyong Park puts("\n");
1095*54fd6939SJiyong Park #endif
1096*54fd6939SJiyong Park
1097*54fd6939SJiyong Park if (abort != 0) {
1098*54fd6939SJiyong Park return;
1099*54fd6939SJiyong Park }
1100*54fd6939SJiyong Park
1101*54fd6939SJiyong Park regs->dec[0] = map_row[17] << 26 |
1102*54fd6939SJiyong Park map_row[16] << 18 |
1103*54fd6939SJiyong Park map_row[15] << 10 |
1104*54fd6939SJiyong Park map_row[14] << 2;
1105*54fd6939SJiyong Park regs->dec[1] = map_row[13] << 26 |
1106*54fd6939SJiyong Park map_row[12] << 18 |
1107*54fd6939SJiyong Park map_row[11] << 10 |
1108*54fd6939SJiyong Park map_row[10] << 2;
1109*54fd6939SJiyong Park regs->dec[2] = map_row[9] << 26 |
1110*54fd6939SJiyong Park map_row[8] << 18 |
1111*54fd6939SJiyong Park map_row[7] << 10 |
1112*54fd6939SJiyong Park map_row[6] << 2;
1113*54fd6939SJiyong Park regs->dec[3] = map_row[5] << 26 |
1114*54fd6939SJiyong Park map_row[4] << 18 |
1115*54fd6939SJiyong Park map_row[3] << 10 |
1116*54fd6939SJiyong Park map_row[2] << 2;
1117*54fd6939SJiyong Park regs->dec[4] = map_row[1] << 26 |
1118*54fd6939SJiyong Park map_row[0] << 18 |
1119*54fd6939SJiyong Park map_col[10] << 10 |
1120*54fd6939SJiyong Park map_col[9] << 2;
1121*54fd6939SJiyong Park regs->dec[5] = map_col[8] << 26 |
1122*54fd6939SJiyong Park map_col[7] << 18 |
1123*54fd6939SJiyong Park map_col[6] << 10 |
1124*54fd6939SJiyong Park map_col[5] << 2;
1125*54fd6939SJiyong Park regs->dec[6] = map_col[4] << 26 |
1126*54fd6939SJiyong Park map_col[3] << 18 |
1127*54fd6939SJiyong Park map_col[2] << 10 |
1128*54fd6939SJiyong Park map_col[1] << 2;
1129*54fd6939SJiyong Park regs->dec[7] = map_col[0] << 26 |
1130*54fd6939SJiyong Park map_ba[1] << 18 |
1131*54fd6939SJiyong Park map_ba[0] << 10 |
1132*54fd6939SJiyong Park map_cid[1] << 2;
1133*54fd6939SJiyong Park regs->dec[8] = map_cid[1] << 26 |
1134*54fd6939SJiyong Park map_cs[1] << 18 |
1135*54fd6939SJiyong Park map_cs[0] << 10 |
1136*54fd6939SJiyong Park map_bg[1] << 2;
1137*54fd6939SJiyong Park regs->dec[9] = map_bg[0] << 26 |
1138*54fd6939SJiyong Park 1;
1139*54fd6939SJiyong Park for (i = 0; i < 10; i++) {
1140*54fd6939SJiyong Park debug("dec[%d] = 0x%x\n", i, regs->dec[i]);
1141*54fd6939SJiyong Park }
1142*54fd6939SJiyong Park #endif
1143*54fd6939SJiyong Park }
skip_caslat(unsigned int tckmin_ps,unsigned int taamin_ps,unsigned int mclk_ps,unsigned int package_3ds)1144*54fd6939SJiyong Park static unsigned int skip_caslat(unsigned int tckmin_ps,
1145*54fd6939SJiyong Park unsigned int taamin_ps,
1146*54fd6939SJiyong Park unsigned int mclk_ps,
1147*54fd6939SJiyong Park unsigned int package_3ds)
1148*54fd6939SJiyong Park {
1149*54fd6939SJiyong Park int i, j, k;
1150*54fd6939SJiyong Park struct cas {
1151*54fd6939SJiyong Park const unsigned int tckmin_ps;
1152*54fd6939SJiyong Park const unsigned int caslat[4];
1153*54fd6939SJiyong Park };
1154*54fd6939SJiyong Park struct speed {
1155*54fd6939SJiyong Park const struct cas *cl;
1156*54fd6939SJiyong Park const unsigned int taamin_ps[4];
1157*54fd6939SJiyong Park };
1158*54fd6939SJiyong Park const struct cas cl_3200[] = {
1159*54fd6939SJiyong Park {625, {0xa00000, 0xb00000, 0xf000000,} },
1160*54fd6939SJiyong Park {750, { 0x20000, 0x60000, 0xe00000,} },
1161*54fd6939SJiyong Park {833, { 0x8000, 0x18000, 0x38000,} },
1162*54fd6939SJiyong Park {937, { 0x4000, 0x4000, 0xc000,} },
1163*54fd6939SJiyong Park {1071, { 0x1000, 0x1000, 0x3000,} },
1164*54fd6939SJiyong Park {1250, { 0x400, 0x400, 0xc00,} },
1165*54fd6939SJiyong Park {1500, { 0, 0x600, 0x200,} },
1166*54fd6939SJiyong Park };
1167*54fd6939SJiyong Park const struct cas cl_2933[] = {
1168*54fd6939SJiyong Park {682, { 0, 0x80000, 0x180000, 0x380000} },
1169*54fd6939SJiyong Park {750, { 0x20000, 0x60000, 0x60000, 0xe0000} },
1170*54fd6939SJiyong Park {833, { 0x8000, 0x18000, 0x18000, 0x38000} },
1171*54fd6939SJiyong Park {937, { 0x4000, 0x4000, 0x4000, 0xc000} },
1172*54fd6939SJiyong Park {1071, { 0x1000, 0x1000, 0x1000, 0x3000} },
1173*54fd6939SJiyong Park {1250, { 0x400, 0x400, 0x400, 0xc00} },
1174*54fd6939SJiyong Park {1500, { 0, 0x200, 0x200, 0x200} },
1175*54fd6939SJiyong Park };
1176*54fd6939SJiyong Park const struct cas cl_2666[] = {
1177*54fd6939SJiyong Park {750, { 0, 0x20000, 0x60000, 0xe0000} },
1178*54fd6939SJiyong Park {833, { 0x8000, 0x18000, 0x18000, 0x38000} },
1179*54fd6939SJiyong Park {937, { 0x4000, 0x4000, 0x4000, 0xc000} },
1180*54fd6939SJiyong Park {1071, { 0x1000, 0x1000, 0x1000, 0x3000} },
1181*54fd6939SJiyong Park {1250, { 0x400, 0x400, 0x400, 0xc00} },
1182*54fd6939SJiyong Park {1500, { 0, 0, 0x200, 0x200} },
1183*54fd6939SJiyong Park };
1184*54fd6939SJiyong Park const struct cas cl_2400[] = {
1185*54fd6939SJiyong Park {833, { 0, 0x8000, 0x18000, 0x38000} },
1186*54fd6939SJiyong Park {937, { 0xc000, 0x4000, 0x4000, 0xc000} },
1187*54fd6939SJiyong Park {1071, { 0x3000, 0x1000, 0x1000, 0x3000} },
1188*54fd6939SJiyong Park {1250, { 0xc00, 0x400, 0x400, 0xc00} },
1189*54fd6939SJiyong Park {1500, { 0, 0x400, 0x200, 0x200} },
1190*54fd6939SJiyong Park };
1191*54fd6939SJiyong Park const struct cas cl_2133[] = {
1192*54fd6939SJiyong Park {937, { 0, 0x4000, 0xc000,} },
1193*54fd6939SJiyong Park {1071, { 0x2000, 0, 0x2000,} },
1194*54fd6939SJiyong Park {1250, { 0x800, 0, 0x800,} },
1195*54fd6939SJiyong Park {1500, { 0, 0x400, 0x200,} },
1196*54fd6939SJiyong Park };
1197*54fd6939SJiyong Park const struct cas cl_1866[] = {
1198*54fd6939SJiyong Park {1071, { 0, 0x1000, 0x3000,} },
1199*54fd6939SJiyong Park {1250, { 0xc00, 0x400, 0xc00,} },
1200*54fd6939SJiyong Park {1500, { 0, 0x400, 0x200,} },
1201*54fd6939SJiyong Park };
1202*54fd6939SJiyong Park const struct cas cl_1600[] = {
1203*54fd6939SJiyong Park {1250, { 0, 0x400, 0xc00,} },
1204*54fd6939SJiyong Park {1500, { 0, 0x400, 0x200,} },
1205*54fd6939SJiyong Park };
1206*54fd6939SJiyong Park const struct speed bin_0[] = {
1207*54fd6939SJiyong Park {cl_3200, {12500, 13750, 15000,} },
1208*54fd6939SJiyong Park {cl_2933, {12960, 13640, 13750, 15000,} },
1209*54fd6939SJiyong Park {cl_2666, {12750, 13500, 13750, 15000,} },
1210*54fd6939SJiyong Park {cl_2400, {12500, 13320, 13750, 15000,} },
1211*54fd6939SJiyong Park {cl_2133, {13130, 13500, 15000,} },
1212*54fd6939SJiyong Park {cl_1866, {12850, 13500, 15000,} },
1213*54fd6939SJiyong Park {cl_1600, {12500, 13500, 15000,} }
1214*54fd6939SJiyong Park };
1215*54fd6939SJiyong Park const struct cas cl_3200_3ds[] = {
1216*54fd6939SJiyong Park {625, { 0xa000000, 0xb000000, 0xf000000,} },
1217*54fd6939SJiyong Park {750, { 0xaa00000, 0xab00000, 0xef00000,} },
1218*54fd6939SJiyong Park {833, { 0xaac0000, 0xaac0000, 0xebc0000,} },
1219*54fd6939SJiyong Park {937, { 0xaab0000, 0xaab0000, 0xeaf0000,} },
1220*54fd6939SJiyong Park {1071, { 0xaaa4000, 0xaaac000, 0xeaec000,} },
1221*54fd6939SJiyong Park {1250, { 0xaaa0000, 0xaaa2000, 0xeaeb000,} },
1222*54fd6939SJiyong Park };
1223*54fd6939SJiyong Park const struct cas cl_2666_3ds[] = {
1224*54fd6939SJiyong Park {750, { 0xa00000, 0xb00000, 0xf00000,} },
1225*54fd6939SJiyong Park {833, { 0xac0000, 0xac0000, 0xbc0000,} },
1226*54fd6939SJiyong Park {937, { 0xab0000, 0xab0000, 0xaf0000,} },
1227*54fd6939SJiyong Park {1071, { 0xaa4000, 0xaac000, 0xaac000,} },
1228*54fd6939SJiyong Park {1250, { 0xaa0000, 0xaaa000, 0xaaa000,} },
1229*54fd6939SJiyong Park };
1230*54fd6939SJiyong Park const struct cas cl_2400_3ds[] = {
1231*54fd6939SJiyong Park {833, { 0xe00000, 0xe40000, 0xec0000, 0xb00000} },
1232*54fd6939SJiyong Park {937, { 0xe00000, 0xe00000, 0xea0000, 0xae0000} },
1233*54fd6939SJiyong Park {1071, { 0xe00000, 0xe04000, 0xeac000, 0xaec000} },
1234*54fd6939SJiyong Park {1250, { 0xe00000, 0xe00000, 0xeaa000, 0xae2000} },
1235*54fd6939SJiyong Park };
1236*54fd6939SJiyong Park const struct cas cl_2133_3ds[] = {
1237*54fd6939SJiyong Park {937, { 0x90000, 0xb0000, 0xf0000,} },
1238*54fd6939SJiyong Park {1071, { 0x84000, 0xac000, 0xec000,} },
1239*54fd6939SJiyong Park {1250, { 0x80000, 0xa2000, 0xe2000,} },
1240*54fd6939SJiyong Park };
1241*54fd6939SJiyong Park const struct cas cl_1866_3ds[] = {
1242*54fd6939SJiyong Park {1071, { 0, 0x4000, 0xc000,} },
1243*54fd6939SJiyong Park {1250, { 0, 0x1000, 0x3000,} },
1244*54fd6939SJiyong Park };
1245*54fd6939SJiyong Park const struct cas cl_1600_3ds[] = {
1246*54fd6939SJiyong Park {1250, { 0, 0x1000, 0x3000,} },
1247*54fd6939SJiyong Park };
1248*54fd6939SJiyong Park const struct speed bin_3ds[] = {
1249*54fd6939SJiyong Park {cl_3200_3ds, {15000, 16250, 17140,} },
1250*54fd6939SJiyong Park {cl_2666_3ds, {15000, 16500, 17140,} },
1251*54fd6939SJiyong Park {cl_2400_3ds, {15000, 15830, 16670, 17140} },
1252*54fd6939SJiyong Park {cl_2133_3ds, {15950, 16880, 17140,} },
1253*54fd6939SJiyong Park {cl_1866_3ds, {15000, 16070, 17140,} },
1254*54fd6939SJiyong Park {cl_1600_3ds, {15000, 16250, 17500,} },
1255*54fd6939SJiyong Park };
1256*54fd6939SJiyong Park const struct speed *bin;
1257*54fd6939SJiyong Park int size;
1258*54fd6939SJiyong Park unsigned int taamin_max, tck_max;
1259*54fd6939SJiyong Park
1260*54fd6939SJiyong Park if (taamin_ps > ((package_3ds != 0) ? 21500 : 18000)) {
1261*54fd6939SJiyong Park ERROR("taamin_ps %u invalid\n", taamin_ps);
1262*54fd6939SJiyong Park return 0;
1263*54fd6939SJiyong Park }
1264*54fd6939SJiyong Park if (package_3ds != 0) {
1265*54fd6939SJiyong Park bin = bin_3ds;
1266*54fd6939SJiyong Park size = ARRAY_SIZE(bin_3ds);
1267*54fd6939SJiyong Park taamin_max = 1250;
1268*54fd6939SJiyong Park tck_max = 1500;
1269*54fd6939SJiyong Park } else {
1270*54fd6939SJiyong Park bin = bin_0;
1271*54fd6939SJiyong Park size = ARRAY_SIZE(bin_0);
1272*54fd6939SJiyong Park taamin_max = 1500;
1273*54fd6939SJiyong Park tck_max = 1600;
1274*54fd6939SJiyong Park }
1275*54fd6939SJiyong Park if (mclk_ps < 625 || mclk_ps > tck_max) {
1276*54fd6939SJiyong Park ERROR("mclk %u invalid\n", mclk_ps);
1277*54fd6939SJiyong Park return 0;
1278*54fd6939SJiyong Park }
1279*54fd6939SJiyong Park
1280*54fd6939SJiyong Park for (i = 0; i < size; i++) {
1281*54fd6939SJiyong Park if (bin[i].cl[0].tckmin_ps >= tckmin_ps) {
1282*54fd6939SJiyong Park break;
1283*54fd6939SJiyong Park }
1284*54fd6939SJiyong Park }
1285*54fd6939SJiyong Park if (i >= size) {
1286*54fd6939SJiyong Park ERROR("speed bin not found\n");
1287*54fd6939SJiyong Park return 0;
1288*54fd6939SJiyong Park }
1289*54fd6939SJiyong Park if (bin[i].cl[0].tckmin_ps > tckmin_ps && i > 0) {
1290*54fd6939SJiyong Park i--;
1291*54fd6939SJiyong Park }
1292*54fd6939SJiyong Park
1293*54fd6939SJiyong Park for (j = 0; j < 4; j++) {
1294*54fd6939SJiyong Park if ((bin[i].taamin_ps[j] == 0) ||
1295*54fd6939SJiyong Park bin[i].taamin_ps[j] >= taamin_ps) {
1296*54fd6939SJiyong Park break;
1297*54fd6939SJiyong Park }
1298*54fd6939SJiyong Park }
1299*54fd6939SJiyong Park
1300*54fd6939SJiyong Park if (j >= 4) {
1301*54fd6939SJiyong Park ERROR("taamin_ps out of range.\n");
1302*54fd6939SJiyong Park return 0;
1303*54fd6939SJiyong Park }
1304*54fd6939SJiyong Park
1305*54fd6939SJiyong Park if ((bin[i].taamin_ps[j] == 0) ||
1306*54fd6939SJiyong Park (bin[i].taamin_ps[j] > taamin_ps && j > 0)) {
1307*54fd6939SJiyong Park j--;
1308*54fd6939SJiyong Park }
1309*54fd6939SJiyong Park
1310*54fd6939SJiyong Park for (k = 0; bin[i].cl[k].tckmin_ps < mclk_ps &&
1311*54fd6939SJiyong Park bin[i].cl[k].tckmin_ps < taamin_max; k++)
1312*54fd6939SJiyong Park ;
1313*54fd6939SJiyong Park if (bin[i].cl[k].tckmin_ps > mclk_ps && k > 0) {
1314*54fd6939SJiyong Park k--;
1315*54fd6939SJiyong Park }
1316*54fd6939SJiyong Park
1317*54fd6939SJiyong Park debug("Skip CL mask for this speed 0x%x\n", bin[i].cl[k].caslat[j]);
1318*54fd6939SJiyong Park
1319*54fd6939SJiyong Park return bin[i].cl[k].caslat[j];
1320*54fd6939SJiyong Park }
1321*54fd6939SJiyong Park
compute_ddrc(const unsigned long clk,const struct memctl_opt * popts,const struct ddr_conf * conf,struct ddr_cfg_regs * regs,const struct dimm_params * pdimm,unsigned int ip_rev)1322*54fd6939SJiyong Park int compute_ddrc(const unsigned long clk,
1323*54fd6939SJiyong Park const struct memctl_opt *popts,
1324*54fd6939SJiyong Park const struct ddr_conf *conf,
1325*54fd6939SJiyong Park struct ddr_cfg_regs *regs,
1326*54fd6939SJiyong Park const struct dimm_params *pdimm,
1327*54fd6939SJiyong Park unsigned int ip_rev)
1328*54fd6939SJiyong Park {
1329*54fd6939SJiyong Park unsigned int cas_latency;
1330*54fd6939SJiyong Park unsigned int caslat_skip;
1331*54fd6939SJiyong Park unsigned int additive_latency;
1332*54fd6939SJiyong Park const unsigned int mclk_ps = get_memory_clk_ps(clk);
1333*54fd6939SJiyong Park int i;
1334*54fd6939SJiyong Park
1335*54fd6939SJiyong Park zeromem(regs, sizeof(struct ddr_cfg_regs));
1336*54fd6939SJiyong Park
1337*54fd6939SJiyong Park if (mclk_ps < pdimm->tckmin_x_ps) {
1338*54fd6939SJiyong Park ERROR("DDR Clk: MCLK cycle is %u ps.\n", mclk_ps);
1339*54fd6939SJiyong Park ERROR("DDR Clk is faster than DIMM can support.\n");
1340*54fd6939SJiyong Park }
1341*54fd6939SJiyong Park
1342*54fd6939SJiyong Park /* calculate cas latency, override first */
1343*54fd6939SJiyong Park cas_latency = (popts->caslat_override != 0) ?
1344*54fd6939SJiyong Park popts->caslat_override_value :
1345*54fd6939SJiyong Park (pdimm->taa_ps + mclk_ps - 1) / mclk_ps;
1346*54fd6939SJiyong Park
1347*54fd6939SJiyong Park /* skip unsupported caslat based on speed bin */
1348*54fd6939SJiyong Park caslat_skip = skip_caslat(pdimm->tckmin_x_ps,
1349*54fd6939SJiyong Park pdimm->taa_ps,
1350*54fd6939SJiyong Park mclk_ps,
1351*54fd6939SJiyong Park pdimm->package_3ds);
1352*54fd6939SJiyong Park debug("Skip caslat 0x%x\n", caslat_skip);
1353*54fd6939SJiyong Park
1354*54fd6939SJiyong Park /* Check if DIMM supports the cas latency */
1355*54fd6939SJiyong Park i = 24;
1356*54fd6939SJiyong Park while (((pdimm->caslat_x & ~caslat_skip & (1 << cas_latency)) == 0) &&
1357*54fd6939SJiyong Park (i-- > 0)) {
1358*54fd6939SJiyong Park cas_latency++;
1359*54fd6939SJiyong Park }
1360*54fd6939SJiyong Park
1361*54fd6939SJiyong Park if (i <= 0) {
1362*54fd6939SJiyong Park ERROR("Failed to find a proper cas latency\n");
1363*54fd6939SJiyong Park return -EINVAL;
1364*54fd6939SJiyong Park }
1365*54fd6939SJiyong Park /* Verify cas latency does not exceed 18ns for DDR4 */
1366*54fd6939SJiyong Park if (cas_latency * mclk_ps > 18000) {
1367*54fd6939SJiyong Park ERROR("cas latency is too large %d\n", cas_latency);
1368*54fd6939SJiyong Park return -EINVAL;
1369*54fd6939SJiyong Park }
1370*54fd6939SJiyong Park
1371*54fd6939SJiyong Park additive_latency = (popts->addt_lat_override != 0) ?
1372*54fd6939SJiyong Park popts->addt_lat_override_value : 0;
1373*54fd6939SJiyong Park
1374*54fd6939SJiyong Park cal_ddr_csn_bnds(regs, popts, conf, pdimm);
1375*54fd6939SJiyong Park cal_ddr_sdram_cfg(clk, regs, popts, pdimm, ip_rev);
1376*54fd6939SJiyong Park cal_ddr_sdram_rcw(clk, regs, popts, pdimm);
1377*54fd6939SJiyong Park cal_timing_cfg(clk, regs, popts, pdimm, conf, cas_latency,
1378*54fd6939SJiyong Park additive_latency);
1379*54fd6939SJiyong Park cal_ddr_dq_mapping(regs, pdimm);
1380*54fd6939SJiyong Park
1381*54fd6939SJiyong Park if (ip_rev >= 0x50500) {
1382*54fd6939SJiyong Park cal_ddr_addr_dec(regs);
1383*54fd6939SJiyong Park }
1384*54fd6939SJiyong Park
1385*54fd6939SJiyong Park cal_ddr_sdram_mode(clk, regs, popts, conf, pdimm, cas_latency,
1386*54fd6939SJiyong Park additive_latency, ip_rev);
1387*54fd6939SJiyong Park cal_ddr_eor(regs, popts);
1388*54fd6939SJiyong Park cal_ddr_data_init(regs);
1389*54fd6939SJiyong Park cal_ddr_sdram_interval(clk, regs, popts, pdimm);
1390*54fd6939SJiyong Park cal_ddr_zq_cntl(regs);
1391*54fd6939SJiyong Park cal_ddr_sr_cntr(regs, popts);
1392*54fd6939SJiyong Park
1393*54fd6939SJiyong Park return 0;
1394*54fd6939SJiyong Park }
1395