blob: dd09dda7fe71638eb5cce7696c98be2939dd1b07 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +01002
Arthur Heymans9eb0b192023-11-07 11:00:21 +01003#include <build.h>
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +01004#include <types.h>
5#include <string.h>
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +01006#include <device/device.h>
7#include <device/smbus.h>
8#include <smbios.h>
9#include <console/console.h>
Vladimir Serbinenko537283d2015-05-21 09:51:00 +020010#include <version.h>
Vladimir Serbinenkoa31a8382014-02-15 19:56:51 +010011#include "lenovo.h"
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010012
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020013#define ERROR_STRING "*INVALID*"
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010014
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110015static struct device *at24rf08c_find_bank(u8 bank)
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020016{
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110017 struct device *dev;
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010018 dev = dev_find_slot_on_smbus(1, 0x54 | bank);
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020019 if (!dev)
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010020 printk(BIOS_WARNING, "EEPROM not found\n");
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020021 return dev;
22}
23
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110024static int at24rf08c_read_byte(struct device *dev, u8 addr)
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020025{
26 int t = -1;
27 int j;
28
Elyes HAOUAS88607a42018-10-05 10:36:45 +020029 /* After a register write AT24RF08C (which we issued in init function)
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020030 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;
Paul Menzel25fc8d12014-02-02 11:48:48 +010036 }
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010037
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020038 return t;
39}
40
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110041static void at24rf08c_read_string_dev(struct device *dev, u8 start,
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020042 u8 len, char *result)
43{
44 int i;
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010045 for (i = 0; i < len; i++) {
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020046 int t = at24rf08c_read_byte(dev, start + i);
47
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010048 if (t < 0x20 || t > 0x7f) {
Elyes HAOUASaf56a772020-07-22 20:36:20 +020049 memcpy(result, ERROR_STRING, sizeof(ERROR_STRING));
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010050 return;
51 }
52 result[i] = t;
53 }
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020054 result[len] = '\0';
55}
56
57static void at24rf08c_read_string(u8 bank, u8 start, u8 len, char *result)
58{
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +110059 struct device *dev;
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020060
61 dev = at24rf08c_find_bank(bank);
Edward O'Callaghan1ab41db2014-11-28 03:31:42 +110062 if (dev == NULL) {
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020063 printk(BIOS_WARNING, "EEPROM not found\n");
Elyes HAOUASaf56a772020-07-22 20:36:20 +020064 memcpy(result, ERROR_STRING, sizeof(ERROR_STRING));
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +020065 return;
66 }
67
68 at24rf08c_read_string_dev(dev, start, len, result);
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010069}
70
71const 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
Elyes HAOUASaf56a772020-07-22 20:36:20 +020079 memset(result, 0, sizeof(result));
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010080 at24rf08c_read_string(0, 0x2e, 7, result);
81
82 already_read = 1;
83 return result;
84}
85
Vladimir Serbinenkoa31a8382014-02-15 19:56:51 +010086const char *lenovo_mainboard_partnumber(void)
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010087{
88 static char result[12];
89 static int already_read;
90
91 if (already_read)
92 return result;
93
Elyes HAOUASaf56a772020-07-22 20:36:20 +020094 memset(result, 0, sizeof(result));
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +010095 at24rf08c_read_string(0, 0x27, 7, result);
96
97 already_read = 1;
98 return result;
99}
100
Vladimir Serbinenkoa31a8382014-02-15 19:56:51 +0100101const char *smbios_mainboard_product_name(void)
102{
103 return lenovo_mainboard_partnumber();
104}
105
Nico Huberebd8a4f2017-11-01 09:49:16 +0100106void smbios_system_set_uuid(u8 *uuid)
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100107{
108 static char result[16];
Martin Roth38ddbfb2019-10-23 21:41:00 -0600109 unsigned int i;
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100110 static int already_read;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100111 struct device *dev;
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100112 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
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100117 if (already_read) {
Elyes HAOUAS9b865b42016-10-03 22:19:16 +0200118 memcpy(uuid, result, 16);
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100119 return;
120 }
121
Elyes HAOUASaf56a772020-07-22 20:36:20 +0200122 memset(result, 0, sizeof(result));
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100123
124 dev = dev_find_slot_on_smbus(1, 0x56);
Edward O'Callaghan1ab41db2014-11-28 03:31:42 +1100125 if (dev == NULL) {
Edward O'Callaghan07d89a02014-11-28 02:48:00 +1100126 printk(BIOS_WARNING, "EEPROM not found\n");
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100127 already_read = 1;
Elyes HAOUAS9b865b42016-10-03 22:19:16 +0200128 memset(uuid, 0, 16);
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100129 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) {
Elyes HAOUASaf56a772020-07-22 20:36:20 +0200144 memset(result, 0, sizeof(result));
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100145 break;
146 }
147 result[remap[i]] = t;
148 }
149
150 already_read = 1;
151
Elyes HAOUAS9b865b42016-10-03 22:19:16 +0200152 memcpy(uuid, result, 16);
Vladimir Serbinenko62adc4c2014-01-23 09:06:08 +0100153}
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +0200154
155const char *smbios_mainboard_version(void)
156{
157 static char result[100];
158 static int already_read;
Edward O'Callaghan2c9d2cf2014-10-27 23:29:29 +1100159 struct device *dev;
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +0200160 int len;
161
162 if (already_read)
163 return result;
164
Elyes HAOUASaf56a772020-07-22 20:36:20 +0200165 memset(result, 0, sizeof(result));
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +0200166
167 dev = at24rf08c_find_bank(2);
Edward O'Callaghan1ab41db2014-11-28 03:31:42 +1100168 if (dev == NULL) {
Elyes HAOUASaf56a772020-07-22 20:36:20 +0200169 memcpy(result, ERROR_STRING, sizeof(ERROR_STRING));
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +0200170 return result;
171 }
172
173 len = at24rf08c_read_byte(dev, 0x26) - 2;
174 if (len < 0 || len > sizeof(result) - 1) {
Elyes HAOUASaf56a772020-07-22 20:36:20 +0200175 memcpy(result, ERROR_STRING, sizeof(ERROR_STRING));
Vladimir Serbinenkoed74dcd2014-08-27 23:22:50 +0200176 return result;
177 }
178
179 at24rf08c_read_string_dev(dev, 0x27, len, result);
180
181 already_read = 1;
182 return result;
183}
Vladimir Serbinenko537283d2015-05-21 09:51:00 +0200184
185const char *smbios_mainboard_bios_version(void)
186{
Vladimir Serbinenko537283d2015-05-21 09:51:00 +0200187 /* Satisfy thinkpad_acpi. */
188 if (strlen(CONFIG_LOCALVERSION))
189 return "CBET4000 " CONFIG_LOCALVERSION;
190
Arthur Heymans9eb0b192023-11-07 11:00:21 +0100191 return "CBET4000 " COREBOOT_VERSION;
Vladimir Serbinenko537283d2015-05-21 09:51:00 +0200192}
Vladimir Serbinenko0afdec42015-05-30 23:08:26 +0200193
194const char *smbios_mainboard_manufacturer(void)
195{
196 return "LENOVO";
197}