xref: /aosp_15_r20/external/coreboot/src/drivers/i2c/at24rf08c/lenovo_serials.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <build.h>
4 #include <types.h>
5 #include <string.h>
6 #include <device/device.h>
7 #include <device/smbus.h>
8 #include <smbios.h>
9 #include <console/console.h>
10 #include <version.h>
11 #include "lenovo.h"
12 
13 #define ERROR_STRING "*INVALID*"
14 
at24rf08c_find_bank(u8 bank)15 static struct device *at24rf08c_find_bank(u8 bank)
16 {
17 	struct device *dev;
18 	dev = dev_find_slot_on_smbus(1, 0x54 | bank);
19 	if (!dev)
20 		printk(BIOS_WARNING, "EEPROM not found\n");
21 	return dev;
22 }
23 
at24rf08c_read_byte(struct device * dev,u8 addr)24 static int at24rf08c_read_byte(struct device *dev, u8 addr)
25 {
26 	int t = -1;
27 	int j;
28 
29 	/* After a register write AT24RF08C (which we issued in init function)
30 	   sometimes stops responding. Retry several times in case of failure.
31 	*/
32 	for (j = 0; j < 100; j++) {
33 		t = smbus_read_byte(dev, addr);
34 		if (t >= 0)
35 			return t;
36 	}
37 
38 	return t;
39 }
40 
at24rf08c_read_string_dev(struct device * dev,u8 start,u8 len,char * result)41 static void at24rf08c_read_string_dev(struct device *dev, u8 start,
42 				      u8 len, char *result)
43 {
44 	int i;
45 	for (i = 0; i < len; i++) {
46 		int t = at24rf08c_read_byte(dev, start + i);
47 
48 		if (t < 0x20 || t > 0x7f) {
49 			memcpy(result, ERROR_STRING, sizeof(ERROR_STRING));
50 			return;
51 		}
52 		result[i] = t;
53 	}
54 	result[len] = '\0';
55 }
56 
at24rf08c_read_string(u8 bank,u8 start,u8 len,char * result)57 static void at24rf08c_read_string(u8 bank, u8 start, u8 len, char *result)
58 {
59 	struct device *dev;
60 
61 	dev = at24rf08c_find_bank(bank);
62 	if (dev == NULL) {
63 		printk(BIOS_WARNING, "EEPROM not found\n");
64 		memcpy(result, ERROR_STRING, sizeof(ERROR_STRING));
65 		return;
66 	}
67 
68 	at24rf08c_read_string_dev(dev, start, len, result);
69 }
70 
smbios_mainboard_serial_number(void)71 const char *smbios_mainboard_serial_number(void)
72 {
73 	static char result[12];
74 	static int already_read;
75 
76 	if (already_read)
77 		return result;
78 
79 	memset(result, 0, sizeof(result));
80 	at24rf08c_read_string(0, 0x2e, 7, result);
81 
82 	already_read = 1;
83 	return result;
84 }
85 
lenovo_mainboard_partnumber(void)86 const char *lenovo_mainboard_partnumber(void)
87 {
88 	static char result[12];
89 	static int already_read;
90 
91 	if (already_read)
92 		return result;
93 
94 	memset(result, 0, sizeof(result));
95 	at24rf08c_read_string(0, 0x27, 7, result);
96 
97 	already_read = 1;
98 	return result;
99 }
100 
smbios_mainboard_product_name(void)101 const char *smbios_mainboard_product_name(void)
102 {
103 	return lenovo_mainboard_partnumber();
104 }
105 
smbios_system_set_uuid(u8 * uuid)106 void smbios_system_set_uuid(u8 *uuid)
107 {
108 	static char result[16];
109 	unsigned int i;
110 	static int already_read;
111 	struct device *dev;
112 	const int remap[16] = {
113 		/* UUID byteswap.  */
114 		3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15
115 	};
116 
117 	if (already_read) {
118 		memcpy(uuid, result, 16);
119 		return;
120 	}
121 
122 	memset(result, 0, sizeof(result));
123 
124 	dev = dev_find_slot_on_smbus(1, 0x56);
125 	if (dev == NULL) {
126 		printk(BIOS_WARNING, "EEPROM not found\n");
127 		already_read = 1;
128 		memset(uuid, 0, 16);
129 		return;
130 	}
131 
132 	for (i = 0; i < 16; i++) {
133 		int t;
134 		int j;
135 		/* After a register write AT24RF08C (which we issued in init function) sometimes stops responding.
136 		   Retry several times in case of failure.
137 		*/
138 		for (j = 0; j < 100; j++) {
139 			t = smbus_read_byte(dev, 0x12 + i);
140 			if (t >= 0)
141 				break;
142 		}
143 		if (t < 0) {
144 			memset(result, 0, sizeof(result));
145 			break;
146 		}
147 		result[remap[i]] = t;
148 	}
149 
150 	already_read = 1;
151 
152 	memcpy(uuid, result, 16);
153 }
154 
smbios_mainboard_version(void)155 const char *smbios_mainboard_version(void)
156 {
157 	static char result[100];
158 	static int already_read;
159 	struct device *dev;
160 	int len;
161 
162 	if (already_read)
163 		return result;
164 
165 	memset(result, 0, sizeof(result));
166 
167 	dev = at24rf08c_find_bank(2);
168 	if (dev == NULL) {
169 		memcpy(result, ERROR_STRING, sizeof(ERROR_STRING));
170 		return result;
171 	}
172 
173 	len = at24rf08c_read_byte(dev, 0x26) - 2;
174 	if (len < 0 || len > sizeof(result) - 1) {
175 		memcpy(result, ERROR_STRING, sizeof(ERROR_STRING));
176 		return result;
177 	}
178 
179 	at24rf08c_read_string_dev(dev, 0x27, len, result);
180 
181 	already_read = 1;
182 	return result;
183 }
184 
smbios_mainboard_bios_version(void)185 const char *smbios_mainboard_bios_version(void)
186 {
187 	/* Satisfy thinkpad_acpi.  */
188 	if (strlen(CONFIG_LOCALVERSION))
189 		return "CBET4000 " CONFIG_LOCALVERSION;
190 
191 	return "CBET4000 " COREBOOT_VERSION;
192 }
193 
smbios_mainboard_manufacturer(void)194 const char *smbios_mainboard_manufacturer(void)
195 {
196 	return "LENOVO";
197 }
198