diff options
Diffstat (limited to 'src/vendorcode/google/chromeos')
-rw-r--r-- | src/vendorcode/google/chromeos/sar.c | 107 |
1 files changed, 83 insertions, 24 deletions
diff --git a/src/vendorcode/google/chromeos/sar.c b/src/vendorcode/google/chromeos/sar.c index 954492b822..fc72dc1348 100644 --- a/src/vendorcode/google/chromeos/sar.c +++ b/src/vendorcode/google/chromeos/sar.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2017 Intel Corp. + * Copyright (C) 2017-2018 Intel Corp. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,6 +12,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + +#include <cbfs.h> #include <console/console.h> #include <lib.h> #include <types.h> @@ -19,44 +21,101 @@ #include <sar.h> #include "cros_vpd.h" -/* Retrieve the wifi SAR limits data from VPD and decode it */ +#define WIFI_SAR_CBFS_FILENAME "wifi_sar_defaults.hex" + +static int load_sar_file_from_cbfs(void *buf, size_t buffer_size) +{ + return cbfs_boot_load_file(WIFI_SAR_CBFS_FILENAME, buf, + buffer_size, CBFS_TYPE_RAW); +} + +/* Retrieve the wifi SAR limits data from VPD and decode it + +For VPD: key,value pair is in this format +"wifi_sar"=[<WRDD><EWRD>][WGDS] + +WIFI SAR data in CBFS file is expected in same format: [<WRDD><EWRD>][WGDS] + +[<WRDD><EWRD>] = NUM_SAR_LIMITS * BYTES_PER_SAR_LIMIT bytes. +[WGDS]=[WGDS_VERSION][WGDS_DATA] + +For [WGDS_VERSION] 0x00, +[WGDS_DATA] = [GROUP#0][GROUP#1][GROUP#2] + +[GROUP#<i>] = + [2.4Ghz – Max Allowed][2.4Ghz – Chain A Offset] + [2.4Ghz – Chain B Offset][5Ghz – Max Allowed] + [5Ghz – Chain A Offset][5Ghz – Chain B Offset] + +[GROUP#0] is for FCC +[GROUP#1] is for Europe/Japan +[GROUP#2] is for ROW + +*/ int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits) { const char *wifi_sar_limit_key = CROS_VPD_WIFI_SAR_NAME; - /* - * cros_vpd_gets() reads in one less than size characters from the VPD + /* cros_vpd_gets() reads in one less than size characters from the VPD * with a terminating null byte ('\0') stored as the last character into - * the buffer, thus the increasing by 1 for buffer_size. - */ + * the buffer, thus the increasing by 1 for buffer_size. */ const size_t buffer_size = (sizeof(struct wifi_sar_limits) / - sizeof(uint8_t)) * 2 + 1; + sizeof(uint8_t)) * 2 + 1; char wifi_sar_limit_str[buffer_size]; uint8_t bin_buffer[sizeof(struct wifi_sar_limits)]; - int i; + size_t sar_cbfs_len, sar_expected_len, bin_buff_adjusted_size; + + /* keep it backward compatible. Some older platform are shipping + without GEO SAR and so older wifi_sar VPD key */ + + sar_expected_len = buffer_size; + bin_buff_adjusted_size = sizeof(struct wifi_sar_limits); + + if (!IS_ENABLED(CONFIG_GEO_SAR_ENABLE)) { + sar_expected_len = buffer_size - + sizeof(struct wifi_sar_delta_table) * + sizeof(uint8_t) * 2; + bin_buff_adjusted_size = sizeof(struct wifi_sar_limits) - + sizeof(struct wifi_sar_delta_table); + } /* Try to read the SAR limit entry from VPD */ if (!cros_vpd_gets(wifi_sar_limit_key, wifi_sar_limit_str, - ARRAY_SIZE(wifi_sar_limit_str))) { - printk(BIOS_ERR, - "Error: Could not locate '%s' in VPD\n", - wifi_sar_limit_key); - return -1; + buffer_size)) { + printk(BIOS_ERR, "Error: Could not locate '%s' in VPD.\n", + wifi_sar_limit_key); + + if (!IS_ENABLED(CONFIG_WIFI_SAR_CBFS)) + return -1; + + printk(BIOS_DEBUG, "Checking CBFS for default SAR values\n"); + + sar_cbfs_len = load_sar_file_from_cbfs( + (void *) wifi_sar_limit_str, + sar_expected_len); + + if (sar_cbfs_len != sar_expected_len) { + printk(BIOS_ERR, "%s has bad len in CBFS\n", + WIFI_SAR_CBFS_FILENAME); + return -1; + } + } else { + /* VPD key "wifi_sar" found. strlen is checked with addition of + * 1 as we have created buffer size 1 char larger for the reason + * mentioned at start of this function itself */ + if (strlen(wifi_sar_limit_str) + 1 != sar_expected_len) { + printk(BIOS_ERR, "WIFI SAR key has bad len in VPD\n"); + return -1; + } } - printk(BIOS_DEBUG, "VPD wifi_sar = %s\n", wifi_sar_limit_str); /* Decode the heximal encoded string to binary values */ - if (hexstrtobin(wifi_sar_limit_str, bin_buffer, - sizeof(struct wifi_sar_limits)) - < sizeof(struct wifi_sar_limits)) { - printk(BIOS_ERR, - "Error: VPD wifi_sar contains non-heximal value!\n"); + if (hexstrtobin(wifi_sar_limit_str, bin_buffer, bin_buff_adjusted_size) + < bin_buff_adjusted_size) { + printk(BIOS_ERR, "Error: wifi_sar contains non-hex value!\n"); return -1; } - /* Fill the sar_limits structure with the decoded data */ - for (i = 0; i < NUM_SAR_LIMITS; i++) - memcpy(sar_limits->sar_limit[i], - &bin_buffer[BYTES_PER_SAR_LIMIT * i], - BYTES_PER_SAR_LIMIT); + memset(sar_limits, 0, sizeof(*sar_limits)); + memcpy(sar_limits, bin_buffer, bin_buff_adjusted_size); return 0; } |