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