blob: 9e58ef33c0b713d6a5749b9a80bf46856c2068d9 [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Arthur Heymans6d7a8c12017-03-07 20:48:14 +01002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Arthur Heymans6d7a8c12017-03-07 20:48:14 +01004#include <console/console.h>
5#include <delay.h>
Angel Pons41e66ac2020-09-15 13:17:23 +02006#include "raminit.h"
Arthur Heymans6d7a8c12017-03-07 20:48:14 +01007#include "x4x.h"
8
9#define MAX_COARSE 15
10#define DQS_HIGH 1
11#define DQS_LOW 0
12
Angel Ponsd0591122021-05-26 14:24:06 +020013#define RESET_CNTL(channel) (0x5d8 + (channel) * 0x400)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010014
15struct rec_timing {
16 u8 medium;
17 u8 coarse;
18 u8 pi;
19 u8 tap;
20};
21
Angel Pons879c4de2020-07-24 16:15:04 +020022static inline void mfence(void)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010023{
24 asm volatile("mfence":::);
25}
26
27static u8 sampledqs(u32 addr, u8 lane, u8 channel)
28{
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010029 u32 sample_offset = 0x400 * channel + 0x561 + lane * 4;
30
Angel Ponsbc15e012021-01-12 23:38:44 +010031 /* Reset the DQS probe, on both channels? */
32 for (u8 i = 0; i < TOTAL_CHANNELS; i++) {
Angel Ponsa5146f32021-03-27 09:35:57 +010033 mchbar_clrbits8(RESET_CNTL(i), 1 << 1);
Angel Ponsbc15e012021-01-12 23:38:44 +010034 udelay(1);
Angel Ponsa5146f32021-03-27 09:35:57 +010035 mchbar_setbits8(RESET_CNTL(i), 1 << 1);
Angel Ponsbc15e012021-01-12 23:38:44 +010036 udelay(1);
37 }
Angel Pons879c4de2020-07-24 16:15:04 +020038 mfence();
Elyes HAOUAS2dbc0952019-05-22 21:44:48 +020039 /* Read strobe */
40 read32((u32 *)addr);
Angel Pons879c4de2020-07-24 16:15:04 +020041 mfence();
Angel Ponsa5146f32021-03-27 09:35:57 +010042 return mchbar_read8(sample_offset) >> 6 & 1;
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010043}
44
Angel Ponsdd7ce4e2021-03-26 23:21:02 +010045static void program_timing(const struct rec_timing *timing, u8 channel, u8 lane)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010046{
47 u32 reg32;
48 u16 reg16;
49 u8 reg8;
50
Angel Ponsdd7ce4e2021-03-26 23:21:02 +010051 printk(RAM_SPEW, " Programming timings:Coarse: %d, Medium: %d, TAP: %d, PI: %d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010052 timing->coarse, timing->medium, timing->tap, timing->pi);
53
Angel Ponsa5146f32021-03-27 09:35:57 +010054 reg32 = mchbar_read32(0x400 * channel + 0x248);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010055 reg32 &= ~0xf0000;
56 reg32 |= timing->coarse << 16;
Angel Ponsa5146f32021-03-27 09:35:57 +010057 mchbar_write32(0x400 * channel + 0x248, reg32);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010058
Angel Ponsa5146f32021-03-27 09:35:57 +010059 reg16 = mchbar_read16(0x400 * channel + 0x58c);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010060 reg16 &= ~(3 << (lane * 2));
61 reg16 |= timing->medium << (lane * 2);
Angel Ponsa5146f32021-03-27 09:35:57 +010062 mchbar_write16(0x400 * channel + 0x58c, reg16);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010063
Angel Ponsa5146f32021-03-27 09:35:57 +010064 reg8 = mchbar_read8(0x400 * channel + 0x560 + lane * 4);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010065 reg8 &= ~0x7f;
66 reg8 |= timing->tap;
67 reg8 |= timing->pi << 4;
Angel Ponsa5146f32021-03-27 09:35:57 +010068 mchbar_write8(0x400 * channel + 0x560 + lane * 4, reg8);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +010069}
70
71static int increase_medium(struct rec_timing *timing)
72{
73 if (timing->medium < 3) {
74 timing->medium++;
75 } else if (timing->coarse < MAX_COARSE) {
76 timing->medium = 0;
77 timing->coarse++;
78 } else {
79 printk(BIOS_ERR, "Cannot increase medium any further.\n");
80 return -1;
81 }
82 return 0;
83}
84
85static int decrease_medium(struct rec_timing *timing)
86{
87 if (timing->medium > 0) {
88 timing->medium--;
89 } else if (timing->coarse > 0) {
90 timing->medium = 3;
91 timing->coarse--;
92 } else {
93 printk(BIOS_ERR, "Cannot lower medium any further.\n");
94 return -1;
95 }
96 return 0;
97}
98
99static int increase_tap(struct rec_timing *timing)
100{
101 if (timing->tap == 14) {
102 if (increase_medium(timing))
103 return -1;
104 timing->tap = 0;
105 } else {
106 timing->tap++;
107 }
108 return 0;
109}
110
111static int decrease_tap(struct rec_timing *timing)
112{
113 if (timing->tap > 0) {
114 timing->tap--;
115 } else {
116 if (decrease_medium(timing))
117 return -1;
118 timing->tap = 14;
119 }
120 return 0;
121}
122
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100123static int decr_coarse_low(u8 channel, u8 lane, u32 addr, struct rec_timing *timing)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100124{
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100125 printk(RAM_DEBUG, " Decreasing coarse until high to low transition is found\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100126 while (sampledqs(addr, lane, channel) != DQS_LOW) {
127 if (timing->coarse == 0) {
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100128 printk(BIOS_CRIT, "Couldn't find DQS-high 0 indicator, halt\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100129 return -1;
130 }
131 timing->coarse--;
132 program_timing(timing, channel, lane);
133 }
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100134 printk(RAM_DEBUG, " DQS low at coarse=%d medium=%d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100135 timing->coarse, timing->medium);
136 return 0;
137}
138
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100139static int fine_search_dqs_high(u8 channel, u8 lane, u32 addr, struct rec_timing *timing)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100140{
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100141 printk(RAM_DEBUG, " Increasing TAP until low to high transition is found\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100142 /*
143 * We use a do while loop since it happens that the strobe read
144 * is inconsistent, with the strobe already high. The current
145 * code flow results in failure later when finding the preamble,
146 * at which DQS needs to be high is often not the case if TAP was
147 * not increased at least once here. Work around this by incrementing
148 * TAP at least once to guarantee searching for preamble start at
149 * DQS high.
150 * This seems to be the result of hysteresis on some settings, where
151 * the DQS probe is influenced by its previous value.
152 */
153 if (sampledqs(addr, lane, channel) == DQS_HIGH) {
154 printk(BIOS_WARNING,
155 "DQS already HIGH... DQS probe is inconsistent!\n"
156 "Continuing....\n");
157 }
158 do {
159 if (increase_tap(timing)) {
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100160 printk(BIOS_CRIT, "Could not find DQS-high on fine search.\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100161 return -1;
162 }
163 program_timing(timing, channel, lane);
164 } while (sampledqs(addr, lane, channel) != DQS_HIGH);
165
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100166 printk(RAM_DEBUG, " DQS high at coarse=%d medium=%d tap:%d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100167 timing->coarse, timing->medium, timing->tap);
168 return 0;
169}
170
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100171static int find_dqs_low(u8 channel, u8 lane, u32 addr, struct rec_timing *timing)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100172{
173 /* Look for DQS low, using quarter steps. */
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100174 printk(RAM_DEBUG, " Increasing medium until DQS LOW is found\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100175 while (sampledqs(addr, lane, channel) != DQS_LOW) {
176 if (increase_medium(timing)) {
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100177 printk(BIOS_CRIT, "Coarse > 15: DQS tuning failed, halt\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100178 return -1;
179 }
180 program_timing(timing, channel, lane);
181 }
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100182 printk(RAM_DEBUG, " DQS low at coarse=%d medium=%d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100183 timing->coarse, timing->medium);
184 return 0;
185}
186static int find_dqs_high(u8 channel, u8 lane, u32 addr,
187 struct rec_timing *timing)
188{
189 /* Look for DQS high, using quarter steps. */
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100190 printk(RAM_DEBUG, " Increasing medium until DQS HIGH is found\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100191 while (sampledqs(addr, lane, channel) != DQS_HIGH) {
192 if (increase_medium(timing)) {
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100193 printk(BIOS_CRIT, "Coarse > 16: DQS tuning failed, halt\n");
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100194 return -1;
195 }
196 program_timing(timing, channel, lane);
197 }
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100198 printk(RAM_DEBUG, " DQS high at coarse=%d medium=%d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100199 timing->coarse, timing->medium);
200 return 0;
201}
202
203static int find_dqs_edge_lowhigh(u8 channel, u8 lane,
204 u32 addr, struct rec_timing *timing)
205{
206 /* Medium search for DQS high. */
207 if (find_dqs_high(channel, lane, addr, timing))
208 return -1;
209
210 /* Go back and perform finer search. */
211 if (decrease_medium(timing))
212 return -1;
213 program_timing(timing, channel, lane);
214 if (fine_search_dqs_high(channel, lane, addr, timing) < 0)
215 return -1;
216
217 return 0;
218}
219
220static int find_preamble(u8 channel, u8 lane, u32 addr,
221 struct rec_timing *timing)
222{
223 /* Add a quarter step */
224 if (increase_medium(timing))
225 return -1;
226 program_timing(timing, channel, lane);
227 /* Verify we are at high */
228 if (sampledqs(addr, lane, channel) != DQS_HIGH) {
229 printk(BIOS_CRIT, "Not at DQS high, d'oh\n");
230 return -1;
231 }
232
233 /* Decrease coarse until LOW is found */
234 if (decr_coarse_low(channel, lane, addr, timing))
235 return -1;
236 return 0;
237}
238
239static int calibrate_receive_enable(u8 channel, u8 lane,
240 u32 addr, struct rec_timing *timing)
241{
242 program_timing(timing, channel, lane);
243 /* Set receive enable bit */
Angel Ponsa5146f32021-03-27 09:35:57 +0100244 mchbar_clrsetbits16(0x400 * channel + 0x588, 3 << (lane * 2), 1 << (lane * 2));
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100245
246 if (find_dqs_low(channel, lane, addr, timing))
247 return -1;
248
249 /* Advance a little further. */
250 if (increase_medium(timing)) {
251 /* A finer search could be implemented */
252 printk(BIOS_WARNING, "Cannot increase medium further");
253 return -1;
254 }
255 program_timing(timing, channel, lane);
256
257 if (find_dqs_edge_lowhigh(channel, lane, addr, timing))
258 return -1;
259
260 /* Go back on fine search */
261 if (decrease_tap(timing))
262 return -1;
263 timing->pi = 3;
264 program_timing(timing, channel, lane);
265
266 if (find_preamble(channel, lane, addr, timing))
267 return -1;
268
269 if (find_dqs_edge_lowhigh(channel, lane, addr, timing))
270 return -1;
271 if (decrease_tap(timing))
272 return -1;
273 timing->pi = 7;
274 program_timing(timing, channel, lane);
275
276 /* Unset receive enable bit */
Angel Ponsa5146f32021-03-27 09:35:57 +0100277 mchbar_clrbits16(0x400 * channel + 0x588, 3 << (lane * 2));
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100278 return 0;
279}
280
Arthur Heymansadc571a2017-09-25 09:40:54 +0200281void rcven(struct sysinfo *s)
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100282{
Arthur Heymans1994e4482017-11-04 07:52:23 +0100283 int rank;
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100284 u8 channel, lane, reg8;
Arthur Heymans1994e4482017-11-04 07:52:23 +0100285 /*
286 * Using the macros below the compiler warns about this possibly being
287 * unitialised.
288 */
289 u32 addr = 0;
Arthur Heymans276049f2017-11-05 05:56:34 +0100290 struct rec_timing timing[TOTAL_BYTELANES];
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100291 u8 mincoarse;
292
Arthur Heymansa4e8f67b2017-12-16 21:04:46 +0100293 printk(BIOS_DEBUG, "Starting DQS receiver enable calibration\n");
294
Angel Ponsa5146f32021-03-27 09:35:57 +0100295 mchbar_clrbits8(0x5d8, 3 << 2);
296 mchbar_clrbits8(0x9d8, 3 << 2);
297 mchbar_clrbits8(0x5dc, 1 << 7);
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100298 FOR_EACH_POPULATED_CHANNEL(s->dimms, channel) {
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100299 mincoarse = 0xff;
Arthur Heymans1994e4482017-11-04 07:52:23 +0100300 /*
301 * Receive enable calibration happens on the first populated
302 * rank on each channel.
303 */
304 FOR_EACH_POPULATED_RANK_IN_CHANNEL(s->dimms, channel, rank) {
305 addr = test_address(channel, rank);
306 break;
307 }
Arthur Heymans276049f2017-11-05 05:56:34 +0100308 FOR_EACH_BYTELANE(lane) {
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100309 printk(BIOS_DEBUG, "Channel %d, Lane %d addr=0x%08x\n",
310 channel, lane, addr);
311 timing[lane].coarse = (s->selected_timings.CAS + 1);
312 switch (lane) {
313 default:
314 case 0:
315 case 1:
316 timing[lane].medium = 0;
317 break;
318 case 2:
319 case 3:
320 timing[lane].medium = 1;
321 break;
322 case 4:
323 case 5:
324 timing[lane].medium = 2;
325 break;
326 case 6:
327 case 7:
328 timing[lane].medium = 3;
329 break;
330 }
331 timing[lane].tap = 0;
332 timing[lane].pi = 0;
333
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100334 if (calibrate_receive_enable(channel, lane, addr, &timing[lane]))
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100335 die("Receive enable calibration failed\n");
336 if (mincoarse > timing[lane].coarse)
337 mincoarse = timing[lane].coarse;
338 }
339 printk(BIOS_DEBUG, "Found min coarse value = %d\n", mincoarse);
Arthur Heymansadc571a2017-09-25 09:40:54 +0200340 s->rcven_t[channel].min_common_coarse = mincoarse;
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100341 printk(BIOS_DEBUG, "Receive enable, final timings:\n");
342 /* Normalise coarse */
Arthur Heymans276049f2017-11-05 05:56:34 +0100343 FOR_EACH_BYTELANE(lane) {
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100344 if (timing[lane].coarse == 0)
345 reg8 = 0;
346 else
347 reg8 = timing[lane].coarse - mincoarse;
Angel Ponsdd7ce4e2021-03-26 23:21:02 +0100348 printk(BIOS_DEBUG,
349 "ch %d lane %d: coarse offset: %d;medium: %d; tap: %d\n",
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100350 channel, lane, reg8, timing[lane].medium,
351 timing[lane].tap);
Arthur Heymansadc571a2017-09-25 09:40:54 +0200352 s->rcven_t[channel].coarse_offset[lane] = reg8;
353 s->rcven_t[channel].medium[lane] = timing[lane].medium;
354 s->rcven_t[channel].tap[lane] = timing[lane].tap;
355 s->rcven_t[channel].pi[lane] = timing[lane].pi;
Angel Ponsa5146f32021-03-27 09:35:57 +0100356 mchbar_clrsetbits16(0x400 * channel + 0x5fa, 3 << (lane * 2),
357 reg8 << (lane * 2));
Arthur Heymans6d7a8c12017-03-07 20:48:14 +0100358 }
359 /* simply use timing[0] to program mincoarse */
360 timing[0].coarse = mincoarse;
361 program_timing(&timing[0], channel, 0);
362 }
363}