/* * Copyright 2008 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * Version 2 as published by the Free Software Foundation. */ #include <common.h> #include <ddr_spd.h> /* used for ddr1 and ddr2 spd */ static int spd_check(const u8 *buf, u8 spd_rev, u8 spd_cksum) { unsigned int cksum = 0; unsigned int i; /* * Check SPD revision supported * Rev 1.2 or less supported by this code */ if (spd_rev > 0x12) { printf("SPD revision %02X not supported by this code\n", spd_rev); return 1; } /* * Calculate checksum */ for (i = 0; i < 63; i++) { cksum += *buf++; } cksum &= 0xFF; if (cksum != spd_cksum) { printf("SPD checksum unexpected. " "Checksum in SPD = %02X, computed SPD = %02X\n", spd_cksum, cksum); return 1; } return 0; } unsigned int ddr1_spd_check(const ddr1_spd_eeprom_t *spd) { const u8 *p = (const u8 *)spd; return spd_check(p, spd->spd_rev, spd->cksum); } unsigned int ddr2_spd_check(const ddr2_spd_eeprom_t *spd) { const u8 *p = (const u8 *)spd; return spd_check(p, spd->spd_rev, spd->cksum); } /* * CRC16 compute for DDR3 SPD * Copied from DDR3 SPD spec. */ static int crc16(char *ptr, int count) { int crc, i; crc = 0; while (--count >= 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 & 0xffff; } unsigned int ddr3_spd_check(const ddr3_spd_eeprom_t *spd) { char *p = (char *)spd; int csum16; int len; char crc_lsb; /* byte 126 */ char crc_msb; /* byte 127 */ /* * SPD byte0[7] - CRC coverage * 0 = CRC covers bytes 0~125 * 1 = CRC covers bytes 0~116 */ len = !(spd->info_size_crc & 0x80) ? 126 : 117; csum16 = crc16(p, len); crc_lsb = (char) (csum16 & 0xff); crc_msb = (char) (csum16 >> 8); if (spd->crc[0] == crc_lsb && spd->crc[1] == crc_msb) { return 0; } else { printf("SPD checksum unexpected.\n" "Checksum lsb in SPD = %02X, computed SPD = %02X\n" "Checksum msb in SPD = %02X, computed SPD = %02X\n", spd->crc[0], crc_lsb, spd->crc[1], crc_msb); return 1; } }