Arthur Heymans (arthur@aheymans.xyz) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/18320
-gerrit
commit 592032919490b2e88d6dca68d127c87cb470f972 Author: Arthur Heymans arthur@aheymans.xyz Date: Fri Feb 10 12:08:16 2017 +0100
device/dram/ddr2: Add common function to select common CAS en freq
This function has a CAS mask as input encoded in the same way as SPD byte 18.
It tries to find the fastest frequency at the lowest possible CAS latency.
Change-Id: I3ab39d38a243edddfde8f70ebd23f79ff774e90e Signed-off-by: Arthur Heymans arthur@aheymans.xyz --- src/device/dram/ddr2.c | 87 ++++++++++++++++++++++++++++++++++++++++++ src/include/device/dram/ddr2.h | 15 +++++++- 2 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/src/device/dram/ddr2.c b/src/device/dram/ddr2.c index b712192..21480eb 100644 --- a/src/device/dram/ddr2.c +++ b/src/device/dram/ddr2.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2017 Patrick Rudolph siro@das-labor.org + * Copyright (C) 2017 Arthur Heymans arthur@aheymans.xyz * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -110,6 +111,21 @@ static u8 spd_get_msbs(u8 c) }
/** + * \brief Return index of MSB set + * + * Returns the index fof MSB set. + */ +static u8 spd_get_lsbs(u8 c) +{ + int i; + for (i = 0; i < 7; i++) + if (c & (1 << i)) + return i; + + return 0; +} + +/** * \brief Decode SPD tck cycle time * * Decodes a raw SPD data from a DDR2 DIMM. @@ -593,3 +609,74 @@ void dram_print_spd_ddr2(const dimm_attr *dimm) print_us(" tPLL : ", dimm->tPLL); print_us(" tRR : ", dimm->tRR); } + +int get_common_freq_cas(u8 max_freq, u8 cas_mask, const dimm_attr *dimm, + int num_dimms, u8 *selected_freq, u8 *selected_cas) +{ + int i, found, high_supp_cas, low_supp_cas; + u8 curr_freq, curr_cas; + + const int ddr2_speeds_table[] = { + TCK_200MHZ, + TCK_266MHZ, + TCK_333MHZ, + TCK_400MHZ, + TCK_533MHZ, + TCK_666MHZ, + TCK_700MHZ, + TCK_800MHZ, + }; + + for (i = 0; i < num_dimms; i++) { + if (dimm[i].dimm_type == SPD_DIMM_TYPE_UNDEFINED) + continue; + cas_mask &= dimm[i].cas_supported; + } + + if (!cas_mask) { + printk(BIOS_DEBUG, "No common supported CAS\n"); + return 1; + } + + high_supp_cas = spd_get_msbs(cas_mask); + low_supp_cas = spd_get_lsbs(cas_mask); + + /* Loop from fast to slow frequency, from low to high CAS latency */ + for (curr_freq = max_freq; + curr_freq >= 0; curr_freq--) { + printram("Trying speed: %d\n", curr_freq); + for (curr_cas = low_supp_cas; + curr_cas <= high_supp_cas; curr_cas++) { + printram(" Trying CAS: %d\n", curr_cas); + found = 1; + for (i = 0; i < num_dimms; i++) { + if (dimm[i].dimm_type == + SPD_DIMM_TYPE_UNDEFINED) + continue; + + printram(" Testing DIMM %d:", i); + if (dimm[i].cycle_time[curr_cas] == 0) { + printram(" CAS not supported"); + found = 0; + break; + } + + if (dimm[i].cycle_time[curr_cas] > + ddr2_speeds_table[curr_freq]) { + printram(" Timing too fast\n"); + found = 0; + break; + } + printram(" ok\n"); + } + if (found) { + *selected_freq = curr_freq; + *selected_cas = curr_cas; + return 0; + } + } + } + + printk(BIOS_DEBUG, "No common CAS Frequency combination possible!\n"); + return 1; +} diff --git a/src/include/device/dram/ddr2.h b/src/include/device/dram/ddr2.h index 236be49..8bfcfc1 100644 --- a/src/include/device/dram/ddr2.h +++ b/src/include/device/dram/ddr2.h @@ -46,6 +46,18 @@ #define TCK_333MHZ 768 #define TCK_266MHZ 960 #define TCK_200MHZ 1280 + +enum dram_freq { + DDR2_200MHZ, + DDR2_266MHZ, + DDR2_333MHZ, + DDR2_400MHZ, + DDR2_533MHZ, + DDR2_666MHZ, + DDR2_700MHZ, + DDR2_800MHZ, +}; + /** @} */
/** @@ -198,6 +210,7 @@ u32 spd_decode_spd_size_ddr2(u8 byte0); u32 spd_decode_eeprom_size_ddr2(u8 byte1); int spd_decode_ddr2(dimm_attr *dimm, spd_raw_data spd); void dram_print_spd_ddr2(const dimm_attr *dimm); - +int get_common_freq_cas(u8 max_freq, u8 cas_mask, const dimm_attr *dimm, + int num_dimms, u8 *selected_freq, u8 *selected_cas);
#endif /* DEVICE_DRAM_DDR2L_H */