device/dram/ddr3: Calculate CRC16 of SPD unique identifier

Specification allows for the unique identifier bytes 117..125
to be excluded of CRC calculation. For such SPD, the CRC
would not identify replacement between two identical DIMM parts,
while memory training needs to be redone.

Change-Id: I8e830018b15c344d9f72f921ab84893f633f7654
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/17486
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
diff --git a/src/device/dram/ddr3.c b/src/device/dram/ddr3.c
index cb5b685..b3bcd68 100644
--- a/src/device/dram/ddr3.c
+++ b/src/device/dram/ddr3.c
@@ -46,6 +46,24 @@
 	return 0;
 }
 
+static u16 crc16(const u8 *ptr, int n_crc)
+{
+	int i;
+	u16 crc = 0;
+
+	while (--n_crc >= 0) {
+		crc = (crc ^ (int)*ptr++) << 8;
+		for (i = 0; i < 8; ++i)
+			if (crc & 0x8000) {
+				crc = (crc << 1) ^ 0x1021;
+			} else {
+				crc = crc << 1;
+			}
+	}
+
+	return crc;
+}
+
 /**
  * \brief Calculate the CRC of a DDR3 SPD
  *
@@ -56,9 +74,7 @@
  */
 u16 spd_ddr3_calc_crc(u8 *spd, int len)
 {
-	int n_crc, i;
-	u8 *ptr;
-	u16 crc;
+	int n_crc;
 
 	/* Find the number of bytes covered by CRC */
 	if (spd[0] & 0x80) {
@@ -71,19 +87,24 @@
 		/* Not enough bytes available to get the CRC */
 		return 0;
 
-	/* Compute the CRC */
-	crc = 0;
-	ptr = spd;
-	while (--n_crc >= 0) {
-		crc = crc ^ (int)*ptr++ << 8;
-		for (i = 0; i < 8; ++i)
-			if (crc & 0x8000) {
-				crc = crc << 1 ^ 0x1021;
-			} else {
-				crc = crc << 1;
-			}
-	}
-	return crc;
+	return crc16(spd, n_crc);
+}
+
+/**
+ * \brief Calculate the CRC of a DDR3 SPD unique identifier
+ *
+ * @param spd pointer to raw SPD data
+ * @param len length of data in SPD
+ *
+ * @return the CRC of SPD data bytes 117..127, or 0 when spd data is truncated.
+ */
+u16 spd_ddr3_calc_unique_crc(u8 *spd, int len)
+{
+	if (len < (117 + 11))
+		/* Not enough bytes available to get the CRC */
+		return 0;
+
+	return crc16(&spd[117], 11);
 }
 
 /**