summaryrefslogtreecommitdiff
path: root/src/vendorcode/google/chromeos/sar.c
blob: 83c1c0ca20d84bae86c5215c1b719a549897516c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* SPDX-License-Identifier: GPL-2.0-only */

#include <cbfs.h>
#include <console/console.h>
#include <drivers/vpd/vpd.h>
#include <lib.h>
#include <sar.h>
#include <stdlib.h>
#include <string.h>
#include <types.h>

#define WIFI_SAR_CBFS_FILENAME	"wifi_sar_defaults.hex"

/*
 * Retrieve WiFi SAR limits data from CBFS and decode it
 * WiFi SAR data is expected in the 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 *filename;
	size_t sar_str_len, sar_bin_len;
	char *sar_str;
	int ret = -1;

	/*
	 * If GEO_SAR_ENABLE is not selected, SAR file does not contain
	 * delta table settings.
	 */
	if (CONFIG(GEO_SAR_ENABLE))
		sar_bin_len = sizeof(struct wifi_sar_limits);
	else
		sar_bin_len = sizeof(struct wifi_sar_limits) -
				sizeof(struct wifi_sar_delta_table);

	/*
	 * Each hex digit is represented as a character in CBFS SAR file. Thus,
	 * the SAR file is double the size of its binary buffer equivalent.
	 * Hence, the buffer size allocated for SAR file is:
	 * `2 * sar_bin_len + 1`
	 * 1 additional byte is allocated to store the terminating '\0'.
	 */
	sar_str_len = 2 * sar_bin_len + 1;
	sar_str = malloc(sar_str_len);

	if (!sar_str) {
		printk(BIOS_ERR, "Failed to allocate space for SAR string!\n");
		return ret;
	}

	printk(BIOS_DEBUG, "Checking CBFS for default SAR values\n");

	filename = get_wifi_sar_cbfs_filename();
	if (filename == NULL)
		filename = WIFI_SAR_CBFS_FILENAME;

	if (cbfs_load(filename, sar_str, sar_str_len) != sar_str_len) {
		printk(BIOS_ERR, "%s has bad len in CBFS\n", filename);
		goto done;
	}

	memset(sar_limits, 0, sizeof(*sar_limits));
	if (hexstrtobin(sar_str, (uint8_t *)sar_limits, sar_bin_len) != sar_bin_len) {
		printk(BIOS_ERR, "Error: wifi_sar contains non-hex value!\n");
		goto done;
	}

	ret = 0;
done:
	free(sar_str);
	return ret;
}

__weak
const char *get_wifi_sar_cbfs_filename(void)
{
	return WIFI_SAR_CBFS_FILENAME;
}