xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/smbus/smbuslib.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <spd_bin.h>
5 #include <device/smbus_def.h>
6 #include <device/smbus_host.h>
7 #include "smbuslib.h"
8 
update_spd_len(struct spd_block * blk)9 static void update_spd_len(struct spd_block *blk)
10 {
11 	u8 i, j = 0;
12 	for (i = 0 ; i < CONFIG_DIMM_MAX; i++)
13 		if (blk->spd_array[i] != NULL)
14 			j |= blk->spd_array[i][SPD_DRAM_TYPE];
15 
16 	/* If spd used is DDR4, then its length is 512 byte. */
17 	if (j == SPD_DRAM_DDR4)
18 		blk->len = SPD_PAGE_LEN_DDR4;
19 	else
20 		blk->len = SPD_PAGE_LEN;
21 }
22 
smbus_read_spd(u8 * spd,u8 addr)23 static void smbus_read_spd(u8 *spd, u8 addr)
24 {
25 	u16 i;
26 	u8 step = 1;
27 
28 	if (CONFIG(SPD_READ_BY_WORD))
29 		step = sizeof(uint16_t);
30 
31 	for (i = 0; i < SPD_PAGE_LEN; i += step) {
32 		if (CONFIG(SPD_READ_BY_WORD))
33 			((u16*)spd)[i / sizeof(uint16_t)] =
34 				 smbus_read_word(addr, i);
35 		else
36 			spd[i] = smbus_read_byte(addr, i);
37 	}
38 }
39 
40 /* return -1 if SMBus errors otherwise return 0 */
get_spd(u8 * spd,u8 addr)41 static int get_spd(u8 *spd, u8 addr)
42 {
43 	if (CONFIG_DIMM_SPD_SIZE > SPD_PAGE_LEN) {
44 		/* Restore to page 0 before reading */
45 		smbus_write_byte(SPD_PAGE_0, 0, 0);
46 	}
47 
48 	/* If address is not 0, it will return CB_ERR(-1) if no dimm */
49 	if (smbus_read_byte(addr, 0) < 0) {
50 		printk(BIOS_INFO, "No memory dimm at address %02X\n",
51 			addr << 1);
52 		return -1;
53 	}
54 
55 	if (i2c_eeprom_read(addr, 0, SPD_PAGE_LEN, spd) < 0) {
56 		printk(BIOS_INFO, "do_i2c_eeprom_read failed, using fallback\n");
57 		smbus_read_spd(spd, addr);
58 	}
59 
60 	/* Check if module is DDR4, DDR4 spd is 512 byte. */
61 	if (spd[SPD_DRAM_TYPE] == SPD_DRAM_DDR4 && CONFIG_DIMM_SPD_SIZE > SPD_PAGE_LEN) {
62 		/* Switch to page 1 */
63 		smbus_write_byte(SPD_PAGE_1, 0, 0);
64 
65 		if (i2c_eeprom_read(addr, 0, SPD_PAGE_LEN, spd + SPD_PAGE_LEN) < 0) {
66 			printk(BIOS_INFO, "do_i2c_eeprom_read failed, using fallback\n");
67 			smbus_read_spd(spd + SPD_PAGE_LEN, addr);
68 		}
69 		/* Restore to page 0 */
70 		smbus_write_byte(SPD_PAGE_0, 0, 0);
71 	}
72 	return 0;
73 }
74 
75 static u8 spd_data[CONFIG_DIMM_MAX * CONFIG_DIMM_SPD_SIZE];
76 
get_spd_smbus(struct spd_block * blk)77 void get_spd_smbus(struct spd_block *blk)
78 {
79 	u8 i;
80 	for (i = 0 ; i < CONFIG_DIMM_MAX; i++) {
81 		if (blk->addr_map[i] == 0) {
82 			blk->spd_array[i] = NULL;
83 			continue;
84 		}
85 
86 		if (get_spd(&spd_data[i * CONFIG_DIMM_SPD_SIZE], blk->addr_map[i]) == 0)
87 			blk->spd_array[i] = &spd_data[i * CONFIG_DIMM_SPD_SIZE];
88 		else
89 			blk->spd_array[i] = NULL;
90 	}
91 
92 	update_spd_len(blk);
93 }
94 
95 /*
96  * get_spd_sn returns the SODIMM serial number. It only supports DDR3 and DDR4.
97  *  return CB_SUCCESS, sn is the serial number and sn=0xffffffff if the dimm is not present.
98  *  return CB_ERR, if dram_type is not supported or addr is a zero.
99  */
get_spd_sn(u8 addr,u32 * sn)100 enum cb_err get_spd_sn(u8 addr, u32 *sn)
101 {
102 	u8 i;
103 	u8 dram_type;
104 	int smbus_ret;
105 
106 	/* addr is not a zero. */
107 	if (addr == 0x0)
108 		return CB_ERR;
109 
110 	if (CONFIG_DIMM_SPD_SIZE > SPD_PAGE_LEN) {
111 		/* Restore to page 0 before reading */
112 		smbus_write_byte(SPD_PAGE_0, 0, 0);
113 	}
114 
115 	/* If dimm is not present, set sn to 0xff. */
116 	smbus_ret = smbus_read_byte(addr, SPD_DRAM_TYPE);
117 	if (smbus_ret < 0) {
118 		printk(BIOS_INFO, "No memory dimm at address %02X\n", addr << 1);
119 		*sn = 0xffffffff;
120 		return CB_SUCCESS;
121 	}
122 
123 	dram_type = smbus_ret & 0xff;
124 
125 	/* Check if module is DDR4, DDR4 spd is 512 byte. */
126 	if (dram_type == SPD_DRAM_DDR4 && CONFIG_DIMM_SPD_SIZE > SPD_PAGE_LEN) {
127 		/* Switch to page 1 */
128 		smbus_write_byte(SPD_PAGE_1, 0, 0);
129 
130 		for (i = 0; i < SPD_SN_LEN; i++)
131 			*((u8 *)sn + i) = smbus_read_byte(addr,
132 						i + DDR4_SPD_SN_OFF);
133 
134 		/* Restore to page 0 */
135 		smbus_write_byte(SPD_PAGE_0, 0, 0);
136 	} else if (dram_type == SPD_DRAM_DDR3) {
137 		for (i = 0; i < SPD_SN_LEN; i++)
138 			*((u8 *)sn + i) = smbus_read_byte(addr,
139 							i + DDR3_SPD_SN_OFF);
140 	} else {
141 		printk(BIOS_ERR, "Unsupported dram_type\n");
142 		return CB_ERR;
143 	}
144 
145 	return CB_SUCCESS;
146 }
147