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