blob: badbc6e3d19c7e1c219a904a499ea20d255b8df5 [file] [log] [blame]
Angel Pons56c1c4d2023-03-22 13:25:09 +01001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <console/console.h>
Elyes Haouasbdd03c22024-05-27 11:20:07 +02004#include <stdio.h>
Angel Pons56c1c4d2023-03-22 13:25:09 +01005#include <string.h>
6#include <types.h>
7
8#include "ec.h"
9#include "mainboard.h"
10#include "vpd.h"
11
Angel Ponsb3274252023-05-10 21:57:45 +020012static void write_invalid_str(char *dest, size_t length)
13{
14 snprintf(dest, length, "%s", "INVALID");
15}
16
Angel Ponsd4c5fc02023-03-27 12:06:08 +020017const struct emi_eeprom_vpd *get_emi_eeprom_vpd(void)
Angel Pons56c1c4d2023-03-22 13:25:09 +010018{
Angel Ponsd4c5fc02023-03-27 12:06:08 +020019 static union {
20 struct emi_eeprom_vpd layout;
21 uint8_t raw[sizeof(struct emi_eeprom_vpd)];
22 } vpd = {0};
Angel Pons56c1c4d2023-03-22 13:25:09 +010023
24 /* Check if cached VPD is valid */
Angel Ponsd4c5fc02023-03-27 12:06:08 +020025 if (vpd.layout.header.revision == VPD_LATEST_REVISION)
26 return &vpd.layout;
Angel Pons56c1c4d2023-03-22 13:25:09 +010027
28 ec_emi_read(vpd.raw, EMI_0_IO_BASE_ADDR, 0, 0, sizeof(vpd.raw));
29
30 /* If the magic value doesn't match, consider EEPROM VPD unreliable */
Angel Ponsd4c5fc02023-03-27 12:06:08 +020031 if (vpd.layout.header.magic != VPD_MAGIC) {
Angel Pons56c1c4d2023-03-22 13:25:09 +010032 printk(BIOS_WARNING, "Atlas VPD: Bad magic value, using fallback defaults\n");
Angel Ponsd4c5fc02023-03-27 12:06:08 +020033 vpd.layout.header.revision = 0;
Angel Pons56c1c4d2023-03-22 13:25:09 +010034 } else {
Angel Ponsd4c5fc02023-03-27 12:06:08 +020035 printk(BIOS_DEBUG, "Atlas VPD: Got revision %u from EC\n",
36 vpd.layout.header.revision);
Angel Pons56c1c4d2023-03-22 13:25:09 +010037 }
38
39 /*
40 * For backwards compatibility, if the VPD from the EC is an older
41 * version, uprev it to the latest version coreboot knows about by
42 * filling in the remaining fields with default values. Should the
43 * EC provide a newer VPD revision, coreboot would downgrade it to
44 * the latest version it knows about as the VPD layout is designed
45 * to be backwards compatible.
46 *
47 * Whenever the value of `VPD_LATEST_REVISION` is incremented, add
48 * a new `case` label just before the `default` label that matches
49 * the second latest revision to initialise the newly-added fields
50 * of the VPD structure with a reasonable fallback value. Note the
51 * intentional falling through.
52 */
Angel Ponsd4c5fc02023-03-27 12:06:08 +020053 switch (vpd.layout.header.revision) {
Angel Pons56c1c4d2023-03-22 13:25:09 +010054 case 0:
55 memset(vpd.raw, 0, sizeof(vpd.raw));
Angel Ponsd4c5fc02023-03-27 12:06:08 +020056 vpd.layout.header.magic = VPD_MAGIC;
Angel Ponsb3274252023-05-10 21:57:45 +020057 write_invalid_str(vpd.layout.serial_number, sizeof(vpd.layout.serial_number));
58 write_invalid_str(vpd.layout.part_number, sizeof(vpd.layout.part_number));
Angel Ponsd4c5fc02023-03-27 12:06:08 +020059 vpd.layout.profile = ATLAS_PROF_UNPROGRAMMED;
Angel Pons56c1c4d2023-03-22 13:25:09 +010060 __fallthrough;
61 default:
62 /* Ensure serial numbers are NULL-terminated, update revision last */
Angel Ponsd4c5fc02023-03-27 12:06:08 +020063 vpd.layout.serial_number[ATLAS_SN_PN_LENGTH - 1] = '\0';
64 vpd.layout.part_number[ATLAS_SN_PN_LENGTH - 1] = '\0';
65 vpd.layout.header.revision = VPD_LATEST_REVISION;
Angel Pons56c1c4d2023-03-22 13:25:09 +010066 break;
67 }
68
Angel Ponsd4c5fc02023-03-27 12:06:08 +020069 return &vpd.layout;
Angel Pons56c1c4d2023-03-22 13:25:09 +010070}