Attention is currently required from: Felix Singer, Nico Huber, Arthur Heymans, Patrick Rudolph. Hello Felix Singer, Nico Huber, Arthur Heymans, Patrick Rudolph,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/49289
to review the following change.
Change subject: nb/intel/sandybridge: Split receive enable calibration ......................................................................
nb/intel/sandybridge: Split receive enable calibration
Move receive enable calibration functions into a separate file.
Change-Id: Ib435eec122b3a3d707e1792b604ad43635b650fa Signed-off-by: Angel Pons th3fanbus@gmail.com --- M src/northbridge/intel/sandybridge/Makefile.inc A src/northbridge/intel/sandybridge/raminit/Makefile.inc A src/northbridge/intel/sandybridge/raminit/rcven.c M src/northbridge/intel/sandybridge/raminit_common.c M src/northbridge/intel/sandybridge/raminit_common.h 5 files changed, 404 insertions(+), 375 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/89/49289/1
diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 6380681..55acc5e 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -26,6 +26,7 @@ romstage-y += raminit_native.c romstage-y += raminit_tables.c romstage-y += ../../../device/dram/ddr3.c +subdirs-y += raminit else romstage-y += raminit_mrc.c cbfs-files-y += mrc.bin diff --git a/src/northbridge/intel/sandybridge/raminit/Makefile.inc b/src/northbridge/intel/sandybridge/raminit/Makefile.inc new file mode 100644 index 0000000..aed6f6a --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit/Makefile.inc @@ -0,0 +1,3 @@ +## SPDX-License-Identifier: GPL-2.0-only + +romstage-y += rcven.c diff --git a/src/northbridge/intel/sandybridge/raminit/rcven.c b/src/northbridge/intel/sandybridge/raminit/rcven.c new file mode 100644 index 0000000..8a4b837 --- /dev/null +++ b/src/northbridge/intel/sandybridge/raminit/rcven.c @@ -0,0 +1,373 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/cpu.h> +#include <assert.h> +#include <commonlib/helpers.h> +#include <console/console.h> +#include <cpu/intel/model_206ax/model_206ax.h> +#include <delay.h> +#include <device/mmio.h> +#include <device/pci_def.h> +#include <device/pci_ops.h> +#include <northbridge/intel/sandybridge/raminit_common.h> +#include <northbridge/intel/sandybridge/raminit_native.h> +#include <northbridge/intel/sandybridge/raminit_tables.h> +#include <northbridge/intel/sandybridge/sandybridge.h> +#include <string.h> +#include <types.h> + +void normalize_rcven(ramctr_timing *ctrl, struct rank_rcven_timings *rvt, int delta_prev) +{ + int lane; + + u8 logic_delay_min = UINT8_MAX; + u8 logic_delay_max = 0; + + FOR_ALL_LANES { + const u8 logic_delay = rvt->rcven[lane] / QCLK_PI; + + logic_delay_min = MIN(logic_delay_min, logic_delay); + logic_delay_max = MAX(logic_delay_max, logic_delay); + } + + FOR_ALL_LANES { + rvt->rcven[lane] -= logic_delay_min * QCLK_PI; + } + rvt->io_latency -= logic_delay_min; + + const int delta_post = logic_delay_max - logic_delay_min; + + if (delta_prev < delta_post) { + rvt->io_latency++; + rvt->rt_latency++; + } else if (delta_prev > delta_post) { + rvt->io_latency--; + rvt->rt_latency--; + } +} + +static void test_rcven(ramctr_timing *ctrl, int channel, int rank) +{ + wait_for_iosav(channel); + + /* Send a burst of 16 back-to-back read commands (4 DCLK apart) */ + iosav_write_read_mpr_sequence(channel, rank, ctrl->tMOD, 1, 3, 15, ctrl->CAS + 36); + + iosav_run_once_and_wait(channel); +} + +static int does_lane_work(ramctr_timing *ctrl, int channel, int rank, int lane) +{ + u32 rcven = ctrl->timings[channel][rank].lanes[lane].rcven; + + return (MCHBAR32(lane_base[lane] + + GDCRTRAININGRESULT(channel, (rcven / 32) & 1)) >> (rcven % 32)) & 1; +} + +#define RCVEN_COARSE_PI_LENGTH (2 * QCLK_PI) + +static void find_rcven_pi_coarse(ramctr_timing *ctrl, int channel, int rank, int *upperA) +{ + int rcven; + int statistics[NUM_LANES][RCVEN_COARSE_PI_LENGTH]; + int lane; + + for (rcven = 0; rcven < RCVEN_COARSE_PI_LENGTH; rcven++) { + FOR_ALL_LANES { + ctrl->timings[channel][rank].lanes[lane].rcven = rcven; + } + program_timings(ctrl, channel); + + test_rcven(ctrl, channel, rank); + + FOR_ALL_LANES { + statistics[lane][rcven] = + !does_lane_work(ctrl, channel, rank, lane); + } + } + FOR_ALL_LANES { + struct run rn = get_longest_zero_run(statistics[lane], RCVEN_COARSE_PI_LENGTH); + ctrl->timings[channel][rank].lanes[lane].rcven = rn.middle; + upperA[lane] = rn.end; + if (upperA[lane] < rn.middle) + upperA[lane] += 2 * QCLK_PI; + + printram("rcven: %d, %d, %d: % 4d-% 4d-% 4d\n", + channel, rank, lane, rn.start, rn.middle, rn.end); + } +} + +static void fine_tune_rcven_pi(ramctr_timing *ctrl, int channel, int rank, int *upperA) +{ + int rcven_delta; + int statistics[NUM_LANES][51] = {0}; + int lane, i; + + for (rcven_delta = -25; rcven_delta <= 25; rcven_delta++) { + + FOR_ALL_LANES { + ctrl->timings[channel][rank].lanes[lane].rcven + = upperA[lane] + rcven_delta + QCLK_PI; + } + program_timings(ctrl, channel); + + for (i = 0; i < 100; i++) { + test_rcven(ctrl, channel, rank); + FOR_ALL_LANES { + statistics[lane][rcven_delta + 25] += + does_lane_work(ctrl, channel, rank, lane); + } + } + } + FOR_ALL_LANES { + int last_zero, first_all; + + for (last_zero = -25; last_zero <= 25; last_zero++) + if (statistics[lane][last_zero + 25]) + break; + + last_zero--; + for (first_all = -25; first_all <= 25; first_all++) + if (statistics[lane][first_all + 25] == 100) + break; + + printram("lane %d: %d, %d\n", lane, last_zero, first_all); + + ctrl->timings[channel][rank].lanes[lane].rcven = + (last_zero + first_all) / 2 + upperA[lane]; + + printram("Aval: %d, %d, %d: % 4d\n", channel, rank, + lane, ctrl->timings[channel][rank].lanes[lane].rcven); + } +} + +/* + * Once the DQS high phase has been found (for each DRAM) the next stage + * is to find out the round trip latency, by locating the preamble cycle. + * This is achieved by trying smaller and smaller roundtrip values until + * the strobe sampling is done on the preamble cycle. + */ +static int find_roundtrip_latency(ramctr_timing *ctrl, int channel, int rank, int *upperA) +{ + int works[NUM_LANES]; + int lane; + + while (1) { + int all_works = 1, some_works = 0; + + program_timings(ctrl, channel); + test_rcven(ctrl, channel, rank); + + FOR_ALL_LANES { + works[lane] = !does_lane_work(ctrl, channel, rank, lane); + + if (works[lane]) + some_works = 1; + else + all_works = 0; + } + + /* If every lane is working, exit */ + if (all_works) + return 0; + + /* + * If all bits are one (everyone is failing), decrement + * the roundtrip value by two, and do another iteration. + */ + if (!some_works) { + /* Guard against roundtrip latency underflow */ + if (ctrl->timings[channel][rank].roundtrip_latency < 2) { + printk(BIOS_EMERG, "Roundtrip latency underflow: %d, %d\n", + channel, rank); + return MAKE_ERR; + } + ctrl->timings[channel][rank].roundtrip_latency -= 2; + printram("4024 -= 2;\n"); + continue; + } + + /* + * Else (if some lanes are failing), increase the rank's + * I/O latency by 2, and increase rcven logic delay by 2 + * on the working lanes, then perform another iteration. + */ + ctrl->timings[channel][rank].io_latency += 2; + printram("4028 += 2;\n"); + + /* Guard against I/O latency overflow */ + if (ctrl->timings[channel][rank].io_latency >= 16) { + printk(BIOS_EMERG, "I/O latency overflow: %d, %d\n", + channel, rank); + return MAKE_ERR; + } + FOR_ALL_LANES if (works[lane]) { + ctrl->timings[channel][rank].lanes[lane].rcven += 2 * QCLK_PI; + upperA[lane] += 2 * QCLK_PI; + printram("increment %d, %d, %d\n", channel, rank, lane); + } + } + return 0; +} + +int get_logic_delay_delta(ramctr_timing *ctrl, int channel, int rank) +{ + int lane; + u16 logic_delay_min = 7; + u16 logic_delay_max = 0; + + FOR_ALL_LANES { + const u16 logic_delay = ctrl->timings[channel][rank].lanes[lane].rcven >> 6; + + logic_delay_min = MIN(logic_delay_min, logic_delay); + logic_delay_max = MAX(logic_delay_max, logic_delay); + } + + if (logic_delay_max < logic_delay_min) { + printk(BIOS_EMERG, "Logic delay max < min (%u < %u): %d, %d\n", + logic_delay_max, logic_delay_min, channel, rank); + } + + assert(logic_delay_max >= logic_delay_min); + + return logic_delay_max - logic_delay_min; +} + +static int align_rt_io_latency(ramctr_timing *ctrl, int channel, int rank, int prev) +{ + int latency_offset = 0; + + /* Get changed maxima */ + const int post = get_logic_delay_delta(ctrl, channel, rank); + + if (prev < post) + latency_offset = +1; + + else if (prev > post) + latency_offset = -1; + + else + latency_offset = 0; + + ctrl->timings[channel][rank].io_latency += latency_offset; + ctrl->timings[channel][rank].roundtrip_latency += latency_offset; + printram("4024 += %d;\n", latency_offset); + printram("4028 += %d;\n", latency_offset); + + return post; +} + +static void compute_final_logic_delay(ramctr_timing *ctrl, int channel, int rank) +{ + u16 logic_delay_min = 7; + int lane; + + FOR_ALL_LANES { + const u16 logic_delay = ctrl->timings[channel][rank].lanes[lane].rcven >> 6; + + logic_delay_min = MIN(logic_delay_min, logic_delay); + } + + if (logic_delay_min >= 2) { + printk(BIOS_WARNING, "Logic delay %u greater than 1: %d %d\n", + logic_delay_min, channel, rank); + } + + FOR_ALL_LANES { + ctrl->timings[channel][rank].lanes[lane].rcven -= logic_delay_min << 6; + } + ctrl->timings[channel][rank].io_latency -= logic_delay_min; + printram("4028 -= %d;\n", logic_delay_min); +} + +int receive_enable_calibration(ramctr_timing *ctrl) +{ + int channel, rank, lane; + int err; + + FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { + int all_high, some_high; + int upperA[NUM_LANES]; + int prev; + + wait_for_iosav(channel); + + iosav_write_prea_sequence(channel, rank, ctrl->tRP, 0); + + iosav_run_once_and_wait(channel); + + const union gdcr_training_mod_reg training_mod = { + .receive_enable_mode = 1, + .training_rank_sel = rank, + .odt_always_on = 1, + }; + MCHBAR32(GDCRTRAININGMOD) = training_mod.raw; + + ctrl->timings[channel][rank].io_latency = 4; + ctrl->timings[channel][rank].roundtrip_latency = 55; + program_timings(ctrl, channel); + + find_rcven_pi_coarse(ctrl, channel, rank, upperA); + + all_high = 1; + some_high = 0; + FOR_ALL_LANES { + if (ctrl->timings[channel][rank].lanes[lane].rcven >= QCLK_PI) + some_high = 1; + else + all_high = 0; + } + + if (all_high) { + ctrl->timings[channel][rank].io_latency--; + printram("4028--;\n"); + FOR_ALL_LANES { + ctrl->timings[channel][rank].lanes[lane].rcven -= QCLK_PI; + upperA[lane] -= QCLK_PI; + + } + } else if (some_high) { + ctrl->timings[channel][rank].roundtrip_latency++; + ctrl->timings[channel][rank].io_latency++; + printram("4024++;\n"); + printram("4028++;\n"); + } + + program_timings(ctrl, channel); + + prev = get_logic_delay_delta(ctrl, channel, rank); + + err = find_roundtrip_latency(ctrl, channel, rank, upperA); + if (err) + return err; + + prev = align_rt_io_latency(ctrl, channel, rank, prev); + + fine_tune_rcven_pi(ctrl, channel, rank, upperA); + + prev = align_rt_io_latency(ctrl, channel, rank, prev); + + compute_final_logic_delay(ctrl, channel, rank); + + align_rt_io_latency(ctrl, channel, rank, prev); + + printram("4/8: %d, %d, % 4d, % 4d\n", channel, rank, + ctrl->timings[channel][rank].roundtrip_latency, + ctrl->timings[channel][rank].io_latency); + + printram("final results:\n"); + FOR_ALL_LANES + printram("Aval: %d, %d, %d: % 4d\n", channel, rank, lane, + ctrl->timings[channel][rank].lanes[lane].rcven); + + MCHBAR32(GDCRTRAININGMOD) = 0; + + toggle_io_reset(); + } + + FOR_ALL_POPULATED_CHANNELS { + program_timings(ctrl, channel); + } + + return 0; +} diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c index 015a14b6f..a03c4dd 100644 --- a/src/northbridge/intel/sandybridge/raminit_common.c +++ b/src/northbridge/intel/sandybridge/raminit_common.c @@ -26,7 +26,7 @@ }
/* Toggle IO reset bit */ -static void toggle_io_reset(void) +void toggle_io_reset(void) { u32 r32 = MCHBAR32(MC_INIT_STATE_G); MCHBAR32(MC_INIT_STATE_G) = r32 | (1 << 5); @@ -915,50 +915,12 @@ } }
-static const u32 lane_base[] = { +const u32 lane_base[NUM_LANES] = { LANEBASE_B0, LANEBASE_B1, LANEBASE_B2, LANEBASE_B3, LANEBASE_B4, LANEBASE_B5, LANEBASE_B6, LANEBASE_B7, LANEBASE_ECC };
-static int get_logic_delay_delta(ramctr_timing *ctrl, int channel, int rank); - -struct rank_rcven_timings { - u16 rcven[NUM_LANES]; - u8 io_latency; - u8 rt_latency; -}; - -static void normalize_rcven(ramctr_timing *ctrl, struct rank_rcven_timings *rvt, int delta_prev) -{ - int lane; - - u8 logic_delay_min = UINT8_MAX; - u8 logic_delay_max = 0; - - FOR_ALL_LANES { - const u8 logic_delay = rvt->rcven[lane] / QCLK_PI; - - logic_delay_min = MIN(logic_delay_min, logic_delay); - logic_delay_max = MAX(logic_delay_max, logic_delay); - } - - FOR_ALL_LANES { - rvt->rcven[lane] -= logic_delay_min * QCLK_PI; - } - rvt->io_latency -= logic_delay_min; - - const int delta_post = logic_delay_max - logic_delay_min; - - if (delta_prev < delta_post) { - rvt->io_latency++; - rvt->rt_latency++; - } else if (delta_prev > delta_post) { - rvt->io_latency--; - rvt->rt_latency--; - } -} - /* Maximum delay for command, control, clock */ #define CCC_MAX_PI (2 * QCLK_PI - 1)
@@ -1111,33 +1073,7 @@ MCHBAR32(SC_IO_LATENCY_ch(channel)) = reg_io_latency; }
-static void test_rcven(ramctr_timing *ctrl, int channel, int rank) -{ - wait_for_iosav(channel); - - /* Send a burst of 16 back-to-back read commands (4 DCLK apart) */ - iosav_write_read_mpr_sequence(channel, rank, ctrl->tMOD, 1, 3, 15, ctrl->CAS + 36); - - iosav_run_once_and_wait(channel); -} - -static int does_lane_work(ramctr_timing *ctrl, int channel, int rank, int lane) -{ - u32 rcven = ctrl->timings[channel][rank].lanes[lane].rcven; - - return (MCHBAR32(lane_base[lane] + - GDCRTRAININGRESULT(channel, (rcven / 32) & 1)) >> (rcven % 32)) & 1; -} - -struct run { - int middle; - int end; - int start; - int all; - int length; -}; - -static struct run get_longest_zero_run(int *seq, int sz) +struct run get_longest_zero_run(int *seq, int sz) { int i, ls; int bl = 0, bs = 0; @@ -1170,314 +1106,6 @@ return ret; }
-#define RCVEN_COARSE_PI_LENGTH (2 * QCLK_PI) - -static void find_rcven_pi_coarse(ramctr_timing *ctrl, int channel, int rank, int *upperA) -{ - int rcven; - int statistics[NUM_LANES][RCVEN_COARSE_PI_LENGTH]; - int lane; - - for (rcven = 0; rcven < RCVEN_COARSE_PI_LENGTH; rcven++) { - FOR_ALL_LANES { - ctrl->timings[channel][rank].lanes[lane].rcven = rcven; - } - program_timings(ctrl, channel); - - test_rcven(ctrl, channel, rank); - - FOR_ALL_LANES { - statistics[lane][rcven] = - !does_lane_work(ctrl, channel, rank, lane); - } - } - FOR_ALL_LANES { - struct run rn = get_longest_zero_run(statistics[lane], RCVEN_COARSE_PI_LENGTH); - ctrl->timings[channel][rank].lanes[lane].rcven = rn.middle; - upperA[lane] = rn.end; - if (upperA[lane] < rn.middle) - upperA[lane] += 2 * QCLK_PI; - - printram("rcven: %d, %d, %d: % 4d-% 4d-% 4d\n", - channel, rank, lane, rn.start, rn.middle, rn.end); - } -} - -static void fine_tune_rcven_pi(ramctr_timing *ctrl, int channel, int rank, int *upperA) -{ - int rcven_delta; - int statistics[NUM_LANES][51] = {0}; - int lane, i; - - for (rcven_delta = -25; rcven_delta <= 25; rcven_delta++) { - - FOR_ALL_LANES { - ctrl->timings[channel][rank].lanes[lane].rcven - = upperA[lane] + rcven_delta + QCLK_PI; - } - program_timings(ctrl, channel); - - for (i = 0; i < 100; i++) { - test_rcven(ctrl, channel, rank); - FOR_ALL_LANES { - statistics[lane][rcven_delta + 25] += - does_lane_work(ctrl, channel, rank, lane); - } - } - } - FOR_ALL_LANES { - int last_zero, first_all; - - for (last_zero = -25; last_zero <= 25; last_zero++) - if (statistics[lane][last_zero + 25]) - break; - - last_zero--; - for (first_all = -25; first_all <= 25; first_all++) - if (statistics[lane][first_all + 25] == 100) - break; - - printram("lane %d: %d, %d\n", lane, last_zero, first_all); - - ctrl->timings[channel][rank].lanes[lane].rcven = - (last_zero + first_all) / 2 + upperA[lane]; - - printram("Aval: %d, %d, %d: % 4d\n", channel, rank, - lane, ctrl->timings[channel][rank].lanes[lane].rcven); - } -} - -/* - * Once the DQS high phase has been found (for each DRAM) the next stage - * is to find out the round trip latency, by locating the preamble cycle. - * This is achieved by trying smaller and smaller roundtrip values until - * the strobe sampling is done on the preamble cycle. - */ -static int find_roundtrip_latency(ramctr_timing *ctrl, int channel, int rank, int *upperA) -{ - int works[NUM_LANES]; - int lane; - - while (1) { - int all_works = 1, some_works = 0; - - program_timings(ctrl, channel); - test_rcven(ctrl, channel, rank); - - FOR_ALL_LANES { - works[lane] = !does_lane_work(ctrl, channel, rank, lane); - - if (works[lane]) - some_works = 1; - else - all_works = 0; - } - - /* If every lane is working, exit */ - if (all_works) - return 0; - - /* - * If all bits are one (everyone is failing), decrement - * the roundtrip value by two, and do another iteration. - */ - if (!some_works) { - /* Guard against roundtrip latency underflow */ - if (ctrl->timings[channel][rank].roundtrip_latency < 2) { - printk(BIOS_EMERG, "Roundtrip latency underflow: %d, %d\n", - channel, rank); - return MAKE_ERR; - } - ctrl->timings[channel][rank].roundtrip_latency -= 2; - printram("4024 -= 2;\n"); - continue; - } - - /* - * Else (if some lanes are failing), increase the rank's - * I/O latency by 2, and increase rcven logic delay by 2 - * on the working lanes, then perform another iteration. - */ - ctrl->timings[channel][rank].io_latency += 2; - printram("4028 += 2;\n"); - - /* Guard against I/O latency overflow */ - if (ctrl->timings[channel][rank].io_latency >= 16) { - printk(BIOS_EMERG, "I/O latency overflow: %d, %d\n", - channel, rank); - return MAKE_ERR; - } - FOR_ALL_LANES if (works[lane]) { - ctrl->timings[channel][rank].lanes[lane].rcven += 2 * QCLK_PI; - upperA[lane] += 2 * QCLK_PI; - printram("increment %d, %d, %d\n", channel, rank, lane); - } - } - return 0; -} - -static int get_logic_delay_delta(ramctr_timing *ctrl, int channel, int rank) -{ - int lane; - u16 logic_delay_min = 7; - u16 logic_delay_max = 0; - - FOR_ALL_LANES { - const u16 logic_delay = ctrl->timings[channel][rank].lanes[lane].rcven >> 6; - - logic_delay_min = MIN(logic_delay_min, logic_delay); - logic_delay_max = MAX(logic_delay_max, logic_delay); - } - - if (logic_delay_max < logic_delay_min) { - printk(BIOS_EMERG, "Logic delay max < min (%u < %u): %d, %d\n", - logic_delay_max, logic_delay_min, channel, rank); - } - - assert(logic_delay_max >= logic_delay_min); - - return logic_delay_max - logic_delay_min; -} - -static int align_rt_io_latency(ramctr_timing *ctrl, int channel, int rank, int prev) -{ - int latency_offset = 0; - - /* Get changed maxima */ - const int post = get_logic_delay_delta(ctrl, channel, rank); - - if (prev < post) - latency_offset = +1; - - else if (prev > post) - latency_offset = -1; - - else - latency_offset = 0; - - ctrl->timings[channel][rank].io_latency += latency_offset; - ctrl->timings[channel][rank].roundtrip_latency += latency_offset; - printram("4024 += %d;\n", latency_offset); - printram("4028 += %d;\n", latency_offset); - - return post; -} - -static void compute_final_logic_delay(ramctr_timing *ctrl, int channel, int rank) -{ - u16 logic_delay_min = 7; - int lane; - - FOR_ALL_LANES { - const u16 logic_delay = ctrl->timings[channel][rank].lanes[lane].rcven >> 6; - - logic_delay_min = MIN(logic_delay_min, logic_delay); - } - - if (logic_delay_min >= 2) { - printk(BIOS_WARNING, "Logic delay %u greater than 1: %d %d\n", - logic_delay_min, channel, rank); - } - - FOR_ALL_LANES { - ctrl->timings[channel][rank].lanes[lane].rcven -= logic_delay_min << 6; - } - ctrl->timings[channel][rank].io_latency -= logic_delay_min; - printram("4028 -= %d;\n", logic_delay_min); -} - -int receive_enable_calibration(ramctr_timing *ctrl) -{ - int channel, rank, lane; - int err; - - FOR_ALL_CHANNELS FOR_ALL_POPULATED_RANKS { - int all_high, some_high; - int upperA[NUM_LANES]; - int prev; - - wait_for_iosav(channel); - - iosav_write_prea_sequence(channel, rank, ctrl->tRP, 0); - - iosav_run_once_and_wait(channel); - - const union gdcr_training_mod_reg training_mod = { - .receive_enable_mode = 1, - .training_rank_sel = rank, - .odt_always_on = 1, - }; - MCHBAR32(GDCRTRAININGMOD) = training_mod.raw; - - ctrl->timings[channel][rank].io_latency = 4; - ctrl->timings[channel][rank].roundtrip_latency = 55; - program_timings(ctrl, channel); - - find_rcven_pi_coarse(ctrl, channel, rank, upperA); - - all_high = 1; - some_high = 0; - FOR_ALL_LANES { - if (ctrl->timings[channel][rank].lanes[lane].rcven >= QCLK_PI) - some_high = 1; - else - all_high = 0; - } - - if (all_high) { - ctrl->timings[channel][rank].io_latency--; - printram("4028--;\n"); - FOR_ALL_LANES { - ctrl->timings[channel][rank].lanes[lane].rcven -= QCLK_PI; - upperA[lane] -= QCLK_PI; - - } - } else if (some_high) { - ctrl->timings[channel][rank].roundtrip_latency++; - ctrl->timings[channel][rank].io_latency++; - printram("4024++;\n"); - printram("4028++;\n"); - } - - program_timings(ctrl, channel); - - prev = get_logic_delay_delta(ctrl, channel, rank); - - err = find_roundtrip_latency(ctrl, channel, rank, upperA); - if (err) - return err; - - prev = align_rt_io_latency(ctrl, channel, rank, prev); - - fine_tune_rcven_pi(ctrl, channel, rank, upperA); - - prev = align_rt_io_latency(ctrl, channel, rank, prev); - - compute_final_logic_delay(ctrl, channel, rank); - - align_rt_io_latency(ctrl, channel, rank, prev); - - printram("4/8: %d, %d, % 4d, % 4d\n", channel, rank, - ctrl->timings[channel][rank].roundtrip_latency, - ctrl->timings[channel][rank].io_latency); - - printram("final results:\n"); - FOR_ALL_LANES - printram("Aval: %d, %d, %d: % 4d\n", channel, rank, lane, - ctrl->timings[channel][rank].lanes[lane].rcven); - - MCHBAR32(GDCRTRAININGMOD) = 0; - - toggle_io_reset(); - } - - FOR_ALL_POPULATED_CHANNELS { - program_timings(ctrl, channel); - } - - return 0; -} - static void test_tx_dq(ramctr_timing *ctrl, int channel, int rank) { int lane; diff --git a/src/northbridge/intel/sandybridge/raminit_common.h b/src/northbridge/intel/sandybridge/raminit_common.h index e13beb7..b8b7d7a 100644 --- a/src/northbridge/intel/sandybridge/raminit_common.h +++ b/src/northbridge/intel/sandybridge/raminit_common.h @@ -4,6 +4,7 @@ #define RAMINIT_COMMON_H
#include <cpu/intel/model_206ax/model_206ax.h> +#include <device/dram/ddr3.h> #include <stdint.h>
#define BASEFREQ 133 @@ -321,6 +322,20 @@ u16 rttnom; } odtmap;
+struct run { + int middle; + int end; + int start; + int all; + int length; +}; + +struct rank_rcven_timings { + u16 rcven[NUM_LANES]; + u8 io_latency; + u8 rt_latency; +}; + /* WARNING: Do not forget to increase MRC_CACHE_VERSION when this struct is changed! */ typedef struct dimm_info_st { dimm_attr dimm[NUM_CHANNELS][NUM_SLOTS]; @@ -442,6 +457,8 @@ #define MAKE_ERR ((channel << 16) | (rank << 8) | 1) #define GET_ERR_CHANNEL(x) (x >> 16)
+extern const u32 lane_base[NUM_LANES]; + void dram_mrscommands(ramctr_timing *ctrl); void program_timings(ramctr_timing *ctrl, int channel); void dram_find_common_params(ramctr_timing *ctrl); @@ -469,8 +486,15 @@ void restore_timings(ramctr_timing *ctrl); int try_init_dram_ddr3(ramctr_timing *ctrl, int fast_boot, int s3resume, int me_uma_size);
+void toggle_io_reset(void); void channel_scrub(ramctr_timing *ctrl); bool get_host_ecc_cap(void); bool get_host_ecc_forced(void);
+struct run get_longest_zero_run(int *seq, int sz); + +/* RCVEN functions */ +int get_logic_delay_delta(ramctr_timing *ctrl, int channel, int rank); +void normalize_rcven(ramctr_timing *ctrl, struct rank_rcven_timings *rvt, int delta_prev); + #endif