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 e66f2169f8cc2f8f977ed2265abde5fb3d615baf 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 CAS and Frequency masks as inputs to support northbridges that have different limits on those. The CAS mask is used as defined in SPD and frequency mask is bitwise mask for supported frequency so e.g. : DDR2_200MH is (1 << 0), DDR2_266MHZ is (1 << 1), etc.
Change-Id: I3ab39d38a243edddfde8f70ebd23f79ff774e90e Signed-off-by: Arthur Heymans arthur@aheymans.xyz --- src/device/dram/ddr2.c | 86 ++++++++++++++++++++++++++++++++++++++++++ src/include/device/dram/ddr2.h | 15 +++++++- 2 files changed, 100 insertions(+), 1 deletion(-)
diff --git a/src/device/dram/ddr2.c b/src/device/dram/ddr2.c index b712192..f520904 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,73 @@ 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 freq_mask, 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 = spd_get_msbs(freq_mask); + curr_freq >= spd_get_lsbs(freq_mask); curr_freq--) { + printram("Trying speed: %d\n", curr_freq); + for (curr_cas = low_supp_cas; + curr_cas <= low_supp_cas; curr_cas++) { + printram(" Trying CAS: %d\n"; curr_freq); + found = 1; + for (i = 0; i < num_dimms; i++) { + if (dimm[i]->dimm_type == + SPD_DIMM_TYPE_UNDEFINED) + continue; + + printram(" Testing DIMM: %d\n", 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; + } + } + 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..24d3379 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 freq_mask, u8 cas_mask, const dimm_attr **dimm, + int num_dimms, u8 *selected_freq, u8 *selected_cas);
#endif /* DEVICE_DRAM_DDR2L_H */