1 /* 2 * Copyright 2008-2014 Freescale Semiconductor, Inc. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * Version 2 as published by the Free Software Foundation. 7 */ 8 9 #include <common.h> 10 #include <ddr_spd.h> 11 12 /* used for ddr1 and ddr2 spd */ 13 static int 14 spd_check(const u8 *buf, u8 spd_rev, u8 spd_cksum) 15 { 16 unsigned int cksum = 0; 17 unsigned int i; 18 19 /* 20 * Check SPD revision supported 21 * Rev 1.X or less supported by this code 22 */ 23 if (spd_rev >= 0x20) { 24 printf("SPD revision %02X not supported by this code\n", 25 spd_rev); 26 return 1; 27 } 28 if (spd_rev > 0x13) { 29 printf("SPD revision %02X not verified by this code\n", 30 spd_rev); 31 } 32 33 /* 34 * Calculate checksum 35 */ 36 for (i = 0; i < 63; i++) { 37 cksum += *buf++; 38 } 39 cksum &= 0xFF; 40 41 if (cksum != spd_cksum) { 42 printf("SPD checksum unexpected. " 43 "Checksum in SPD = %02X, computed SPD = %02X\n", 44 spd_cksum, cksum); 45 return 1; 46 } 47 48 return 0; 49 } 50 51 unsigned int 52 ddr1_spd_check(const ddr1_spd_eeprom_t *spd) 53 { 54 const u8 *p = (const u8 *)spd; 55 56 return spd_check(p, spd->spd_rev, spd->cksum); 57 } 58 59 unsigned int 60 ddr2_spd_check(const ddr2_spd_eeprom_t *spd) 61 { 62 const u8 *p = (const u8 *)spd; 63 64 return spd_check(p, spd->spd_rev, spd->cksum); 65 } 66 67 /* 68 * CRC16 compute for DDR3 SPD 69 * Copied from DDR3 SPD spec. 70 */ 71 static int 72 crc16(char *ptr, int count) 73 { 74 int crc, i; 75 76 crc = 0; 77 while (--count >= 0) { 78 crc = crc ^ (int)*ptr++ << 8; 79 for (i = 0; i < 8; ++i) 80 if (crc & 0x8000) 81 crc = crc << 1 ^ 0x1021; 82 else 83 crc = crc << 1; 84 } 85 return crc & 0xffff; 86 } 87 88 unsigned int 89 ddr3_spd_check(const ddr3_spd_eeprom_t *spd) 90 { 91 char *p = (char *)spd; 92 int csum16; 93 int len; 94 char crc_lsb; /* byte 126 */ 95 char crc_msb; /* byte 127 */ 96 97 /* 98 * SPD byte0[7] - CRC coverage 99 * 0 = CRC covers bytes 0~125 100 * 1 = CRC covers bytes 0~116 101 */ 102 103 len = !(spd->info_size_crc & 0x80) ? 126 : 117; 104 csum16 = crc16(p, len); 105 106 crc_lsb = (char) (csum16 & 0xff); 107 crc_msb = (char) (csum16 >> 8); 108 109 if (spd->crc[0] == crc_lsb && spd->crc[1] == crc_msb) { 110 return 0; 111 } else { 112 printf("SPD checksum unexpected.\n" 113 "Checksum lsb in SPD = %02X, computed SPD = %02X\n" 114 "Checksum msb in SPD = %02X, computed SPD = %02X\n", 115 spd->crc[0], crc_lsb, spd->crc[1], crc_msb); 116 return 1; 117 } 118 } 119 120 unsigned int ddr4_spd_check(const struct ddr4_spd_eeprom_s *spd) 121 { 122 char *p = (char *)spd; 123 int csum16; 124 int len; 125 char crc_lsb; /* byte 126 */ 126 char crc_msb; /* byte 127 */ 127 128 len = 126; 129 csum16 = crc16(p, len); 130 131 crc_lsb = (char) (csum16 & 0xff); 132 crc_msb = (char) (csum16 >> 8); 133 134 if (spd->crc[0] != crc_lsb || spd->crc[1] != crc_msb) { 135 printf("SPD checksum unexpected.\n" 136 "Checksum lsb in SPD = %02X, computed SPD = %02X\n" 137 "Checksum msb in SPD = %02X, computed SPD = %02X\n", 138 spd->crc[0], crc_lsb, spd->crc[1], crc_msb); 139 return 1; 140 } 141 142 p = (char *)((ulong)spd + 128); 143 len = 126; 144 csum16 = crc16(p, len); 145 146 crc_lsb = (char) (csum16 & 0xff); 147 crc_msb = (char) (csum16 >> 8); 148 149 if (spd->mod_section.uc[126] != crc_lsb || 150 spd->mod_section.uc[127] != crc_msb) { 151 printf("SPD checksum unexpected.\n" 152 "Checksum lsb in SPD = %02X, computed SPD = %02X\n" 153 "Checksum msb in SPD = %02X, computed SPD = %02X\n", 154 spd->mod_section.uc[126], 155 crc_lsb, spd->mod_section.uc[127], 156 crc_msb); 157 return 1; 158 } 159 160 return 0; 161 } 162