summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/drivers/intel/wifi/Kconfig24
-rw-r--r--src/drivers/intel/wifi/Makefile.inc4
-rw-r--r--src/drivers/intel/wifi/chip.h3
-rw-r--r--src/drivers/intel/wifi/wifi.c55
-rw-r--r--src/include/sar.h26
-rw-r--r--src/vendorcode/google/chromeos/sar.c107
6 files changed, 191 insertions, 28 deletions
diff --git a/src/drivers/intel/wifi/Kconfig b/src/drivers/intel/wifi/Kconfig
index 1e6be6dfd0..3cf0446648 100644
--- a/src/drivers/intel/wifi/Kconfig
+++ b/src/drivers/intel/wifi/Kconfig
@@ -11,7 +11,9 @@ config USE_SAR
default n
help
Enable it when wifi driver uses SAR configuration feature.
- VPD entry "wifi_sar" is required to support it.
+ VPD entry "wifi_sar" is read to get SAR settings, if its
+ not found driver may look into CBFS for default settigs.
+ WIFI_SAR_CBFS is option to enable CBFS lookup.
config SAR_ENABLE
bool
@@ -23,6 +25,26 @@ config DSAR_ENABLE
default n
depends on USE_SAR
+config GEO_SAR_ENABLE
+ bool
+ default n
+ depends on USE_SAR
+
+config WIFI_SAR_CBFS
+ bool
+ default n
+ depends on USE_SAR
+ help
+ wifi driver would look for "wifi_sar" vpd key and load SAR settings from
+ it, if the vpd key is not found then the driver tries to look for sar
+ settings from CBFS with file name wifi_sar_defaults.hex.
+ So OEM/ODM can override wifi sar with VPD.
+
+config WIFI_SAR_CBFS_FILEPATH
+ string "The cbfs file which has WIFI SAR defaults"
+ depends on WIFI_SAR_CBFS
+ default "src/mainboard/$(MAINBOARDDIR)/wifi_sar_defaults.hex"
+
config DSAR_SET_NUM
hex "Number of SAR sets when D-SAR is enabled"
default 0x3
diff --git a/src/drivers/intel/wifi/Makefile.inc b/src/drivers/intel/wifi/Makefile.inc
index aab811c1c4..c354c0b89b 100644
--- a/src/drivers/intel/wifi/Makefile.inc
+++ b/src/drivers/intel/wifi/Makefile.inc
@@ -12,3 +12,7 @@
#
ramstage-$(CONFIG_DRIVERS_INTEL_WIFI) += wifi.c
+
+cbfs-files-$(CONFIG_WIFI_SAR_CBFS) += wifi_sar_defaults.hex
+wifi_sar_defaults.hex-file := $(call strip_quotes,$(CONFIG_WIFI_SAR_CBFS_FILEPATH))
+wifi_sar_defaults.hex-type := raw
diff --git a/src/drivers/intel/wifi/chip.h b/src/drivers/intel/wifi/chip.h
index 0871874ba7..1b3c2a5834 100644
--- a/src/drivers/intel/wifi/chip.h
+++ b/src/drivers/intel/wifi/chip.h
@@ -28,6 +28,9 @@
/* EWRD Domain type */
#define EWRD_DOMAIN_TYPE_WIFI 0x7
+/* WGDS Domain type */
+#define WGDS_DOMAIN_TYPE_WIFI 0x7
+
struct drivers_intel_wifi_config {
unsigned wake; /* Wake pin for ACPI _PRW */
};
diff --git a/src/drivers/intel/wifi/wifi.c b/src/drivers/intel/wifi/wifi.c
index 3ef66aad2a..4b96a0297c 100644
--- a/src/drivers/intel/wifi/wifi.c
+++ b/src/drivers/intel/wifi/wifi.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2014 Vladimir Serbinenko
+ * Copyright (C) 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
@@ -75,6 +76,7 @@ static void emit_sar_acpi_structures(void)
{
int i, j, package_size;
struct wifi_sar_limits sar_limits;
+ struct wifi_sar_delta_table *wgds;
/* Retrieve the sar limits data */
if (get_wifi_sar_limits(&sar_limits) < 0) {
@@ -135,6 +137,59 @@ static void emit_sar_acpi_structures(void)
acpigen_write_byte(sar_limits.sar_limit[i][j]);
acpigen_pop_len();
acpigen_pop_len();
+
+
+ if (!IS_ENABLED(CONFIG_GEO_SAR_ENABLE))
+ return;
+
+ /*
+ * Name ("WGDS", Package() {
+ * Revision,
+ * Package() {
+ * DomainType, // 0x7:WiFi
+ * WgdsWiFiSarDeltaGroup1PowerMax1, // Group 1 FCC 2400 Max
+ * WgdsWiFiSarDeltaGroup1PowerChainA1, // Group 1 FCC 2400 A Offset
+ * WgdsWiFiSarDeltaGroup1PowerChainB1, // Group 1 FCC 2400 B Offset
+ * WgdsWiFiSarDeltaGroup1PowerMax2, // Group 1 FCC 5200 Max
+ * WgdsWiFiSarDeltaGroup1PowerChainA2, // Group 1 FCC 5200 A Offset
+ * WgdsWiFiSarDeltaGroup1PowerChainB2, // Group 1 FCC 5200 B Offset
+ * WgdsWiFiSarDeltaGroup2PowerMax1, // Group 2 EC Jap 2400 Max
+ * WgdsWiFiSarDeltaGroup2PowerChainA1, // Group 2 EC Jap 2400 A Offset
+ * WgdsWiFiSarDeltaGroup2PowerChainB1, // Group 2 EC Jap 2400 B Offset
+ * WgdsWiFiSarDeltaGroup2PowerMax2, // Group 2 EC Jap 5200 Max
+ * WgdsWiFiSarDeltaGroup2PowerChainA2, // Group 2 EC Jap 5200 A Offset
+ * WgdsWiFiSarDeltaGroup2PowerChainB2, // Group 2 EC Jap 5200 B Offset
+ * WgdsWiFiSarDeltaGroup3PowerMax1, // Group 3 ROW 2400 Max
+ * WgdsWiFiSarDeltaGroup3PowerChainA1, // Group 3 ROW 2400 A Offset
+ * WgdsWiFiSarDeltaGroup3PowerChainB1, // Group 3 ROW 2400 B Offset
+ * WgdsWiFiSarDeltaGroup3PowerMax2, // Group 3 ROW 5200 Max
+ * WgdsWiFiSarDeltaGroup3PowerChainA2, // Group 3 ROW 5200 A Offset
+ * WgdsWiFiSarDeltaGroup3PowerChainB2, // Group 3 ROW 5200 B Offset
+ * }
+ * })
+ */
+
+ wgds = &sar_limits.wgds;
+ acpigen_write_name("WGDS");
+ acpigen_write_package(2);
+ acpigen_write_dword(wgds->version);
+ /* Emit 'Domain Type' +
+ * Group specific delta of power ( 6 bytes * NUM_WGDS_SAR_GROUPS )
+ */
+ package_size = sizeof(sar_limits.wgds.group) + 1;
+ acpigen_write_package(package_size);
+ acpigen_write_dword(WGDS_DOMAIN_TYPE_WIFI);
+ for (i = 0; i < SAR_NUM_WGDS_GROUPS; i++) {
+ acpigen_write_byte(wgds->group[i].power_max_2400mhz);
+ acpigen_write_byte(wgds->group[i].power_chain_a_2400mhz);
+ acpigen_write_byte(wgds->group[i].power_chain_b_2400mhz);
+ acpigen_write_byte(wgds->group[i].power_max_5200mhz);
+ acpigen_write_byte(wgds->group[i].power_chain_a_5200mhz);
+ acpigen_write_byte(wgds->group[i].power_chain_b_5200mhz);
+ }
+
+ acpigen_pop_len();
+ acpigen_pop_len();
}
static void intel_wifi_fill_ssdt(struct device *dev)
diff --git a/src/include/sar.h b/src/include/sar.h
index 4653dd33ae..e1e0fcb2d7 100644
--- a/src/include/sar.h
+++ b/src/include/sar.h
@@ -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
@@ -15,22 +15,42 @@
#ifndef _SAR_H_
#define _SAR_H_
+#include <compiler.h>
#include <stdint.h>
#define NUM_SAR_LIMITS 4
#define BYTES_PER_SAR_LIMIT 10
+enum {
+ SAR_FCC,
+ SAR_EUROPE_JAPAN,
+ SAR_REST_OF_WORLD,
+ SAR_NUM_WGDS_GROUPS
+};
+
+struct wifi_sar_delta_table {
+ uint8_t version;
+ struct {
+ uint8_t power_max_2400mhz;
+ uint8_t power_chain_a_2400mhz;
+ uint8_t power_chain_b_2400mhz;
+ uint8_t power_max_5200mhz;
+ uint8_t power_chain_a_5200mhz;
+ uint8_t power_chain_b_5200mhz;
+ } __packed group[SAR_NUM_WGDS_GROUPS];
+} __packed;
/* Wifi SAR limit table structure */
struct wifi_sar_limits {
/* Total 4 SAR limit sets, each has 10 bytes */
uint8_t sar_limit[NUM_SAR_LIMITS][BYTES_PER_SAR_LIMIT];
-};
+ struct wifi_sar_delta_table wgds;
+} __packed;
/*
* Retrieve the SAR limits data from VPD and decode it.
* sar_limits: Pointer to wifi_sar_limits where the resulted data is stored
*
- * Returns: 0 on success, -1 on errors (The VPD entry doesn't exist, or the
+ * Returns: 0 on success, -1 on errors (The VPD entry doesn't exist, or the
* VPD entry contains non-heximal value.)
*/
int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits);
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;
}