Rob Barnes has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/45343 )
Change subject: device/dram: Add method for converting MHz to MT/s ......................................................................
device/dram: Add method for converting MHz to MT/s
Add method for converting DDR4 speed in MHz to MT/s. Checks that MHz is within a speed grade range.
BUG=b:167155849 TEST=ddr4-test unit test
Change-Id: I1433f028afb794fe3e397b03f5bd0565494c8130 Signed-off-by: Rob Barnes robbarnes@google.com --- M src/device/dram/ddr4.c M src/include/device/dram/ddr4.h M tests/device/Makefile.inc A tests/device/ddr4-test.c 4 files changed, 143 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/43/45343/1
diff --git a/src/device/dram/ddr4.c b/src/device/dram/ddr4.c index 429a9d2..0d4c1e3 100644 --- a/src/device/dram/ddr4.c +++ b/src/device/dram/ddr4.c @@ -9,6 +9,53 @@ #include <smbios.h> #include <types.h>
+/** + * DDR4 speed attributes derived from JEDEC 79-4C tables 169 & 170 + * + * min_clock_mhz = 1000/max_tCk_avg(ns) + * max_clock_mhz = 1000/min_tCk_avg(ns) + * reported_mts = Standard reported DDR4 speed in MT/s + * May be 1 less than the actual max MT/s + */ +static const ddr4_speed_attr ddr4_speeds[] = { + [DDR4_UNSPECIFIED] = {}, + [DDR4_1600] = { + .min_clock_mhz = 667, + .max_clock_mhz = 800, + .reported_mts = 1600 + }, + [DDR4_1866]{ + .min_clock_mhz = 800, + .max_clock_mhz = 934, + .reported_mts = 1866 + }, + [DDR4_2133]{ + .min_clock_mhz = 934, + .max_clock_mhz = 1067, + .reported_mts = 2133 + }, + [DDR4_2400]{ + .min_clock_mhz = 1067, + .max_clock_mhz = 1200, + .reported_mts = 2400 + }, + [DDR4_2666]{ + .min_clock_mhz = 1200, + .max_clock_mhz = 1333, + .reported_mts = 2666 + }, + [DDR4_2933]{ + .min_clock_mhz = 1333, + .max_clock_mhz = 1466, + .reported_mts = 2933 + }, + [DDR4_3200]{ + .min_clock_mhz = 1466, + .max_clock_mhz = 1600, + .reported_mts = 3200 + } +}; + typedef enum { BLOCK_0, /* Base Configuration and DRAM Parameters */ BLOCK_1, @@ -68,6 +115,33 @@ } }
+/** + * Converts DDR4 clock speed in MHz to the standard reported speed in MT/s + */ +uint16_t ddr4_speed_mhz_to_reported_mts(uint16_t speed_mhz) +{ + for (enum ddr4_speed_grade speed = DDR4_MIN; speed <= DDR4_MAX; speed++) { + const ddr4_speed_attr speed_attr = ddr4_speed_attributes(speed); + if (speed_mhz > speed_attr.min_clock_mhz && + speed_mhz <= speed_attr.max_clock_mhz) { + return speed_attr.reported_mts; + } + } + printk(BIOS_ERR, "DDR4 speed of %d MHz is out of range", speed_mhz); + return 0; +} + +/** + * Gets DDR4 speed attributes for a given DDR4 speed grade + */ +const ddr4_speed_attr ddr4_speed_attributes(enum ddr4_speed_grade speed) +{ + if (speed < DDR4_MIN || speed > DDR4_MAX) { + printk(BIOS_ERR, "Invalid DDR4 speed grade"); + return ddr4_speeds[DDR4_UNSPECIFIED]; + } + return ddr4_speeds[speed]; +}
/** * \brief Decode the raw SPD data diff --git a/src/include/device/dram/ddr4.h b/src/include/device/dram/ddr4.h index f258fa9..75dbaf1 100644 --- a/src/include/device/dram/ddr4.h +++ b/src/include/device/dram/ddr4.h @@ -70,4 +70,27 @@ const u16 selected_freq, const dimm_attr *info);
+enum ddr4_speed_grade { + DDR4_UNSPECIFIED, + DDR4_1600, + DDR4_1866, + DDR4_2133, + DDR4_2400, + DDR4_2666, + DDR4_2933, + DDR4_3200, + DDR4_MIN = DDR4_1600, + DDR4_MAX = DDR4_3200 +}; + +typedef struct ddr4_speed_attr_st { + uint32_t min_clock_mhz; // exclusive + uint32_t max_clock_mhz; // inclusive + uint32_t reported_mts; +} ddr4_speed_attr; + +const ddr4_speed_attr ddr4_speed_attributes(enum ddr4_speed_grade speed); + +uint16_t ddr4_speed_mhz_to_reported_mts(uint16_t speed_mhz); + #endif /* DEVICE_DRAM_DDR4L_H */ diff --git a/tests/device/Makefile.inc b/tests/device/Makefile.inc index 10223c5..4626c3c 100644 --- a/tests/device/Makefile.inc +++ b/tests/device/Makefile.inc @@ -1,7 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only
tests-y += i2c-test +tests-y += ddr4-test
i2c-test-srcs += tests/device/i2c-test.c i2c-test-srcs += src/device/i2c.c i2c-test-mocks += platform_i2c_transfer + +ddr4-test-srcs += tests/device/ddr4-test.c +ddr4-test-srcs += tests/stubs/console.c +ddr4-test-srcs += src/device/dram/ddr4.c \ No newline at end of file diff --git a/tests/device/ddr4-test.c b/tests/device/ddr4-test.c new file mode 100644 index 0000000..0a9831d --- /dev/null +++ b/tests/device/ddr4-test.c @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <device/dram/ddr4.h> +#include <tests/test.h> + +static void ddr4_speed_mhz_to_mts_test(void **state) +{ + assert_int_equal(0, ddr4_speed_mhz_to_reported_mts(0)); + assert_int_equal(0, ddr4_speed_mhz_to_reported_mts(667)); + + assert_int_equal(1600, ddr4_speed_mhz_to_reported_mts(668)); + assert_int_equal(1600, ddr4_speed_mhz_to_reported_mts(800)); + + assert_int_equal(1866, ddr4_speed_mhz_to_reported_mts(801)); + assert_int_equal(1866, ddr4_speed_mhz_to_reported_mts(933)); + assert_int_equal(1866, ddr4_speed_mhz_to_reported_mts(934)); + + assert_int_equal(2133, ddr4_speed_mhz_to_reported_mts(1066)); + assert_int_equal(2133, ddr4_speed_mhz_to_reported_mts(1067)); + + assert_int_equal(2400, ddr4_speed_mhz_to_reported_mts(1200)); + + assert_int_equal(2666, ddr4_speed_mhz_to_reported_mts(1333)); + + assert_int_equal(2933, ddr4_speed_mhz_to_reported_mts(1466)); + + assert_int_equal(3200, ddr4_speed_mhz_to_reported_mts(1467)); + assert_int_equal(3200, ddr4_speed_mhz_to_reported_mts(1600)); + + assert_int_equal(0, ddr4_speed_mhz_to_reported_mts(1601)); + assert_int_equal(0, ddr4_speed_mhz_to_reported_mts(INT16_MAX)); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(ddr4_speed_mhz_to_mts_test) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +}