15 #define CxRDTy_MCHBAR(ch, bl) (0x14b0 + ((ch) * 0x0100) + ((7 - (bl)) * 4))
16 #define CxRDTy_T_SHIFT 20
17 #define CxRDTy_T_MASK (0xf << CxRDTy_T_SHIFT)
18 #define CxRDTy_T(t) (((t) << CxRDTy_T_SHIFT) & CxRDTy_T_MASK)
19 #define CxRDTy_P_SHIFT 16
20 #define CxRDTy_P_MASK (0x7 << CxRDTy_P_SHIFT)
21 #define CxRDTy_P(p) (((p) << CxRDTy_P_SHIFT) & CxRDTy_P_MASK)
23 0xfefefefe, 0x7f7f7f7f, 0xbebebebe, 0xdfdfdfdf,
24 0xeeeeeeee, 0xf7f7f7f7, 0xfafafafa, 0xfdfdfdfd,
25 0x00000000, 0x81818181, 0x40404040, 0x21212121,
26 0x10101010, 0x09090909, 0x04040404, 0x03030303,
27 0x10101010, 0x11111111, 0xeeeeeeee, 0xefefefef,
28 0x10101010, 0x11111111, 0xeeeeeeee, 0xefefefef,
29 0x10101010, 0xefefefef, 0x10101010, 0xefefefef,
30 0x10101010, 0xefefefef, 0x10101010, 0xefefefef,
31 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
32 0x00000000, 0xffffffff, 0x00000000, 0x00000000,
34 #define READ_TIMING_P_SHIFT 3
35 #define READ_TIMING_P_BOUND (1 << READ_TIMING_P_SHIFT)
36 #define READ_TIMING_T_BOUND 14
42 const int lane,
const int channel,
45 printk(msg_lvl,
"%sbyte lane %d, ch %d: %d.%d\n",
46 msg, lane, channel, timing->
t, timing->
p);
55 while (timing->
p < 0) {
61 "Timing underflow during read training.\n");
67 "Timing overflow during read training.\n");
93 const int lane_offset = lane & 4;
94 const int lane_mask = 0xff << ((lane & ~4) << 3);
96 for (i = 0; i < addresses->
count; ++i) {
101 if ((read & lane_mask) != (good & lane_mask))
142 "Read training failure: limits too narrow.\n");
175 die(
"Read training failure: lower bound.\n");
181 upper.
t = lower.
t + 1;
192 const int mean_p = (lower.
p + upper.
p) >> 1;
210 for (i = 0; i < addresses.
count; ++i) {
218 for (i = 0; i < 8; ++i)
229 for (i = 0; i < 8; ++i) {
231 bytes[(
ch * 8) + i] =
253 for (i = 0; i < 8; ++i) {
254 const int t = bytes[(
ch * 8) + i] >> 4;
255 const int p = bytes[(
ch * 8) + i] & 7;
261 "%d on channel %d: %d.%d\n", i,
ch, t, p);
277 #define CxWRTy_T_SHIFT 28
278 #define CxWRTy_T_MASK (0xf << CxWRTy_T_SHIFT)
279 #define CxWRTy_T(t) (((t) << CxWRTy_T_SHIFT) & CxWRTy_T_MASK)
280 #define CxWRTy_P_SHIFT 24
281 #define CxWRTy_P_MASK (0x7 << CxWRTy_P_SHIFT)
282 #define CxWRTy_P(p) (((p) << CxWRTy_P_SHIFT) & CxWRTy_P_MASK)
283 #define CxWRTy_F_SHIFT 18
284 #define CxWRTy_F_MASK (0x3 << CxWRTy_F_SHIFT)
285 #define CxWRTy_F(f) (((f) << CxWRTy_F_SHIFT) & CxWRTy_F_MASK)
286 #define CxWRTy_D_SHIFT 16
287 #define CxWRTy_D_MASK (0x3 << CxWRTy_D_SHIFT)
288 #define CxWRTy_BELOW_D (0x3 << CxWRTy_D_SHIFT)
289 #define CxWRTy_ABOVE_D (0x1 << CxWRTy_D_SHIFT)
291 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
292 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
293 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
294 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
295 0xefefefef, 0x10101010, 0xefefefef, 0x10101010,
296 0xefefefef, 0x10101010, 0xefefefef, 0x10101010,
297 0xefefefef, 0x10101010, 0xefefefef, 0x10101010,
298 0xefefefef, 0x10101010, 0xefefefef, 0x10101010,
299 0xefefefef, 0xeeeeeeee, 0x11111111, 0x10101010,
300 0xefefefef, 0xeeeeeeee, 0x11111111, 0x10101010,
301 0xefefefef, 0xeeeeeeee, 0x11111111, 0x10101010,
302 0xefefefef, 0xeeeeeeee, 0x11111111, 0x10101010,
303 0x03030303, 0x04040404, 0x09090909, 0x10101010,
304 0x21212121, 0x40404040, 0x81818181, 0x00000000,
305 0x03030303, 0x04040404, 0x09090909, 0x10101010,
306 0x21212121, 0x40404040, 0x81818181, 0x00000000,
307 0xfdfdfdfd, 0xfafafafa, 0xf7f7f7f7, 0xeeeeeeee,
308 0xdfdfdfdf, 0xbebebebe, 0x7f7f7f7f, 0xfefefefe,
309 0xfdfdfdfd, 0xfafafafa, 0xf7f7f7f7, 0xeeeeeeee,
310 0xdfdfdfdf, 0xbebebebe, 0x7f7f7f7f, 0xfefefefe,
315 { 0xffffffff, 0x00000000 }, { 0x00000000, 0x00000000 },
316 { 0x00000000, 0xffffffff }, { 0x00000000, 0x00000000 },
319 { 0x0000ffff, 0x00000000 }, { 0xffff0000, 0x00000000 },
320 { 0x00000000, 0x0000ffff }, { 0x00000000, 0xffff0000 },
325 { 0xff00ff00, 0x00000000 }, { 0x00ff00ff, 0x00000000 },
326 { 0x00000000, 0xff00ff00 }, { 0x00000000, 0x00ff00ff },
328 #define WRITE_TIMING_P_SHIFT 3
329 #define WRITE_TIMING_P_BOUND (1 << WRITE_TIMING_P_SHIFT)
330 #define WRITE_TIMING_F_BOUND 4
338 const int group,
const int channel,
341 printk(msg_lvl,
"%sgroup %d, ch %d: %d.%d.%d\n",
342 msg, group, channel, timing->
f, timing->
t, timing->
p);
351 while (timing->
p < 0) {
355 while (timing->
t >= timing->
t_bound) {
359 while (timing->
t < 0) {
365 "Timing underflow during write training.\n");
372 "Timing overflow during write training.\n");
384 const u32 d_bounds[2][2] = { { 1, 6 }, { 2, 9 } };
389 const int f = timing->
f;
390 const int t = timing->
t;
391 const int p = (memclk1067 && (((t == 9) && (timing->
p >= 4)) ||
392 ((t == 10) && (timing->
p < 4))))
408 const u32 *
const masks)
417 for (i = 0; i < addresses->
count; ++i) {
418 const unsigned int addr = addresses->
addr[i];
420 for (off = 0; off < 640; off += 8) {
428 for (off = 0; off < 640; off += 8) {
431 if ((read1 & masks[0]) != (good & masks[0]))
432 goto _bad_timing_out;
434 if ((read2 & masks[1]) != (good & masks[1]))
435 goto _bad_timing_out;
448 const u32 masks[][2],
const int memclk1067,
459 if ((lower->
f <= 0) && (lower->
t <= 0))
475 const u32 masks[][2],
const int memclk1067,
482 "Write training failure; limits too narrow.\n");
504 const u32 masks[][2],
const int memclk1067)
506 const int t_bound = memclk1067 ? 12 : 11;
508 upper = { 0, 0, t_bound, 0 };
514 lower.
t = (reg >> 12) & 0xf;
515 lower.
p = (reg >> 8) & 0x7;
516 lower.
f = ((reg >> 2) & 0x3) - 1;
519 masks, memclk1067, &lower) < 0)
520 die(
"Write training failure: lower bound.\n");
526 upper.t = lower.
t + 3;
531 masks, memclk1067, &upper) < 0)
539 upper.t += upper.f * upper.t_bound;
542 const int mean_p = (lower.
p + upper.p) >> 1;
553 const int cardF[] = { dimms[0].
card_type == 0xf,
563 if ((dimms[0].card_type != 0) && (cardF[0] == cardF[1])) {
575 const u32 (*
const masks)[2] = (!cardF[
ch])
578 for (group = 0; group < 4; ++group) {
579 if (!masks[group][0] && !masks[group][1])
582 ch, group, &
addr[
ch], masks, memclk1067);
594 for (i = 0; i < 4; ++i) {
596 bytes[(
ch * 8) + (i * 2)] =
600 bytes[(
ch * 8) + (i * 2) + 1] =
611 const int t_bound = memclk1067 ? 12 : 11;
622 for (i = 0; i < 4; ++i) {
624 timing.
f = bytes[(
ch * 8) + (i * 2) + 1] & 3;
625 timing.
t = bytes[(
ch * 8) + (i * 2)] >> 4;
626 timing.
p = bytes[(
ch * 8) + (i * 2)] & 7;
629 "on channel %d: %d.%d.%d\n",
630 i,
ch, timing.
f, timing.
t, timing.
p);
static void write32(void *addr, uint32_t val)
static uint32_t read32(const void *addr)
static const u32 pattern[8]
#define printk(level,...)
void __noreturn die(const char *fmt,...)
static __always_inline uint8_t mchbar_read8(const uintptr_t offset)
#define mchbar_setbits32(addr, set)
static __always_inline void mchbar_write8(const uintptr_t offset, const uint8_t value)
static __always_inline void mchbar_write32(const uintptr_t offset, const uint32_t value)
#define mchbar_setbits8(addr, set)
static __always_inline uint32_t mchbar_read32(const uintptr_t offset)
#define FOR_EACH_POPULATED_CHANNEL(dimms, idx)
#define CMOS_READ_TRAINING
#define FOR_EACH_POPULATED_RANK(dimms, ch, r)
#define FOR_EACH_POPULATED_RANK_IN_CHANNEL(dimms, ch, r)
#define FOR_EACH_CHANNEL(idx)
void raminit_reset_readwrite_pointers(void)
#define CxWRTy_MCHBAR(ch, s)
#define RANKS_PER_CHANNEL
u32 raminit_get_rank_addr(unsigned int channel, unsigned int rank)
#define CMOS_WRITE_TRAINING
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
static void cmos_write(unsigned char val, unsigned char addr)
static unsigned char cmos_read(unsigned char addr)
static struct dramc_channel const ch[2]
static void read_training_store_results(void)
static const u32 write_training_schedule[]
#define WRITE_TIMING_F_BOUND
static void perform_write_training(const int memclk1067, const dimminfo_t *const dimms)
static int read_training_test(const int channel, const int lane, const address_bunch_t *const addresses)
void raminit_read_training(const dimminfo_t *const dimms, const int s3resume)
#define CxRDTy_MCHBAR(ch, bl)
static int normalize_write_timing(write_timing_t *const timing)
void raminit_write_training(const mem_clock_t ddr3clock, const dimminfo_t *const dimms, const int s3resume)
static void write_training_restore_results(const int memclk1067)
#define WRITE_TIMING_P_BOUND
static int write_training_find_lower(const int ch, const int group, const address_bunch_t *const addresses, const u32 masks[][2], const int memclk1067, write_timing_t *const lower)
static int program_read_timing(const int ch, const int lane, read_timing_t *const timing)
static int write_training_find_upper(const int ch, const int group, const address_bunch_t *const addresses, const u32 masks[][2], const int memclk1067, write_timing_t *const upper)
static void read_training_per_lane(const int channel, const int lane, const address_bunch_t *const addresses)
static int program_write_timing(const int ch, const int group, write_timing_t *const timing, int memclk1067)
static void write_training_per_group(const int ch, const int group, const address_bunch_t *const addresses, const u32 masks[][2], const int memclk1067)
static const u32 write_training_bytelane_masks_f[4][2]
static int read_training_find_upper(const int channel, const int lane, const address_bunch_t *const addresses, read_timing_t *const upper)
static int read_training_find_lower(const int channel, const int lane, const address_bunch_t *const addresses, read_timing_t *const lower)
static const u32 write_training_bytelane_masks_abc[2][4][2]
static void print_write_timing(const int msg_lvl, const char *const msg, const int group, const int channel, const write_timing_t *const timing)
#define READ_TIMING_T_BOUND
static const u32 read_training_schedule[]
static int normalize_read_timing(read_timing_t *const timing)
static void write_training_store_results(void)
static void read_training_restore_results(void)
static int write_training_test(const address_bunch_t *const addresses, const u32 *const masks)
#define WRITE_TIMING_P_SHIFT
static void print_read_timing(const int msg_lvl, const char *const msg, const int lane, const int channel, const read_timing_t *const timing)
#define READ_TIMING_P_BOUND
#define READ_TIMING_P_SHIFT
static void perform_read_training(const dimminfo_t *const dimms)
u32 addr[RANKS_PER_CHANNEL]