Angel Pons | 3ef916f | 2020-04-02 23:49:13 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 2 | |
| 3 | #include <cbfs.h> |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 4 | #include <console/console.h> |
Robbie Zhang | feb4ef6 | 2017-01-09 15:28:24 -0800 | [diff] [blame] | 5 | #include <lib.h> |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 6 | #include <types.h> |
| 7 | #include <string.h> |
| 8 | #include <sar.h> |
Patrick Rudolph | 28cee59 | 2018-03-08 15:43:12 +0100 | [diff] [blame] | 9 | #include <drivers/vpd/vpd.h> |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 10 | |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 11 | #define WIFI_SAR_CBFS_FILENAME "wifi_sar_defaults.hex" |
Patrick Rudolph | 28cee59 | 2018-03-08 15:43:12 +0100 | [diff] [blame] | 12 | #define CROS_VPD_WIFI_SAR_NAME "wifi_sar" |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 13 | |
| 14 | static int load_sar_file_from_cbfs(void *buf, size_t buffer_size) |
| 15 | { |
Justin TerAvest | c650d6c | 2018-12-14 11:05:03 -0700 | [diff] [blame] | 16 | const char *filename = get_wifi_sar_cbfs_filename(); |
| 17 | if (filename == NULL) |
| 18 | filename = WIFI_SAR_CBFS_FILENAME; |
Julius Werner | 834b3ec | 2020-03-04 16:52:08 -0800 | [diff] [blame^] | 19 | return cbfs_load(filename, buf, buffer_size); |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 20 | } |
| 21 | |
| 22 | /* Retrieve the wifi SAR limits data from VPD and decode it |
| 23 | |
| 24 | For VPD: key,value pair is in this format |
| 25 | "wifi_sar"=[<WRDD><EWRD>][WGDS] |
| 26 | |
| 27 | WIFI SAR data in CBFS file is expected in same format: [<WRDD><EWRD>][WGDS] |
| 28 | |
| 29 | [<WRDD><EWRD>] = NUM_SAR_LIMITS * BYTES_PER_SAR_LIMIT bytes. |
| 30 | [WGDS]=[WGDS_VERSION][WGDS_DATA] |
| 31 | |
| 32 | For [WGDS_VERSION] 0x00, |
| 33 | [WGDS_DATA] = [GROUP#0][GROUP#1][GROUP#2] |
| 34 | |
| 35 | [GROUP#<i>] = |
| 36 | [2.4Ghz – Max Allowed][2.4Ghz – Chain A Offset] |
| 37 | [2.4Ghz – Chain B Offset][5Ghz – Max Allowed] |
| 38 | [5Ghz – Chain A Offset][5Ghz – Chain B Offset] |
| 39 | |
| 40 | [GROUP#0] is for FCC |
| 41 | [GROUP#1] is for Europe/Japan |
| 42 | [GROUP#2] is for ROW |
| 43 | |
| 44 | */ |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 45 | int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits) |
| 46 | { |
| 47 | const char *wifi_sar_limit_key = CROS_VPD_WIFI_SAR_NAME; |
Patrick Rudolph | 28cee59 | 2018-03-08 15:43:12 +0100 | [diff] [blame] | 48 | /* vpd_gets() reads in one less than size characters from the VPD |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 49 | * with a terminating null byte ('\0') stored as the last character into |
Jacob Garber | 9172b69 | 2019-06-26 16:18:16 -0600 | [diff] [blame] | 50 | * the buffer, thus the increasing by 1 for the buffer size. */ |
| 51 | char wifi_sar_limit_str[2 * sizeof(struct wifi_sar_limits) + 1]; |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 52 | uint8_t bin_buffer[sizeof(struct wifi_sar_limits)]; |
Jacob Garber | 9172b69 | 2019-06-26 16:18:16 -0600 | [diff] [blame] | 53 | const size_t buffer_size = ARRAY_SIZE(wifi_sar_limit_str); |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 54 | size_t sar_cbfs_len, sar_expected_len, bin_buff_adjusted_size; |
| 55 | |
| 56 | /* keep it backward compatible. Some older platform are shipping |
| 57 | without GEO SAR and so older wifi_sar VPD key */ |
| 58 | |
| 59 | sar_expected_len = buffer_size; |
| 60 | bin_buff_adjusted_size = sizeof(struct wifi_sar_limits); |
| 61 | |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 62 | if (!CONFIG(GEO_SAR_ENABLE)) { |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 63 | sar_expected_len = buffer_size - |
| 64 | sizeof(struct wifi_sar_delta_table) * |
| 65 | sizeof(uint8_t) * 2; |
| 66 | bin_buff_adjusted_size = sizeof(struct wifi_sar_limits) - |
| 67 | sizeof(struct wifi_sar_delta_table); |
| 68 | } |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 69 | |
| 70 | /* Try to read the SAR limit entry from VPD */ |
Patrick Rudolph | 28cee59 | 2018-03-08 15:43:12 +0100 | [diff] [blame] | 71 | if (!vpd_gets(wifi_sar_limit_key, wifi_sar_limit_str, |
Jonathan Zhang | a9117ed | 2020-05-28 11:02:13 -0700 | [diff] [blame] | 72 | buffer_size, VPD_RO_THEN_RW)) { |
Maulik V Vaghela | 0fd62f5 | 2020-11-11 12:44:28 +0530 | [diff] [blame] | 73 | printk(BIOS_DEBUG, "Could not locate '%s' in VPD.\n", |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 74 | wifi_sar_limit_key); |
| 75 | |
Julius Werner | cd49cce | 2019-03-05 16:53:33 -0800 | [diff] [blame] | 76 | if (!CONFIG(WIFI_SAR_CBFS)) |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 77 | return -1; |
| 78 | |
| 79 | printk(BIOS_DEBUG, "Checking CBFS for default SAR values\n"); |
| 80 | |
| 81 | sar_cbfs_len = load_sar_file_from_cbfs( |
| 82 | (void *) wifi_sar_limit_str, |
| 83 | sar_expected_len); |
| 84 | |
| 85 | if (sar_cbfs_len != sar_expected_len) { |
| 86 | printk(BIOS_ERR, "%s has bad len in CBFS\n", |
| 87 | WIFI_SAR_CBFS_FILENAME); |
| 88 | return -1; |
| 89 | } |
| 90 | } else { |
| 91 | /* VPD key "wifi_sar" found. strlen is checked with addition of |
| 92 | * 1 as we have created buffer size 1 char larger for the reason |
| 93 | * mentioned at start of this function itself */ |
| 94 | if (strlen(wifi_sar_limit_str) + 1 != sar_expected_len) { |
| 95 | printk(BIOS_ERR, "WIFI SAR key has bad len in VPD\n"); |
| 96 | return -1; |
| 97 | } |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 98 | } |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 99 | |
| 100 | /* Decode the heximal encoded string to binary values */ |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 101 | if (hexstrtobin(wifi_sar_limit_str, bin_buffer, bin_buff_adjusted_size) |
| 102 | < bin_buff_adjusted_size) { |
| 103 | printk(BIOS_ERR, "Error: wifi_sar contains non-hex value!\n"); |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 104 | return -1; |
| 105 | } |
| 106 | |
Pratik Prajapati | 7fd1e4b | 2017-08-11 14:06:57 -0700 | [diff] [blame] | 107 | memset(sar_limits, 0, sizeof(*sar_limits)); |
| 108 | memcpy(sar_limits, bin_buffer, bin_buff_adjusted_size); |
Robbie Zhang | ed84002 | 2016-12-23 11:43:07 -0800 | [diff] [blame] | 109 | return 0; |
| 110 | } |
Justin TerAvest | c650d6c | 2018-12-14 11:05:03 -0700 | [diff] [blame] | 111 | |
| 112 | __weak |
| 113 | const char *get_wifi_sar_cbfs_filename(void) |
| 114 | { |
Kevin Chiu | cc69f7b | 2020-08-21 20:56:04 +0800 | [diff] [blame] | 115 | return WIFI_SAR_CBFS_FILENAME; |
Justin TerAvest | c650d6c | 2018-12-14 11:05:03 -0700 | [diff] [blame] | 116 | } |