1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /** @file
8  * @brief Coexistence functions
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/drivers/gpio.h>
16 
17 #include "coex.h"
18 #include "coex_struct.h"
19 #include "fmac_main.h"
20 #include "fmac_api.h"
21 
22 LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
23 
24 extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
25 static struct nrf_wifi_ctx_zep *rpu_ctx = &rpu_drv_priv_zep.rpu_ctx_zep;
26 
27 #define CH_BASE_ADDRESS ABS_EXT_SYS_WLANSYSCOEX_CH_CONTROL
28 #define COEX_CONFIG_FIXED_PARAMS 4
29 #define COEX_REG_CFG_OFFSET_SHIFT 24
30 
31 /* copied from uccp530_77_registers_ext_sys_bus.h of UCCP toolkit */
32 #define EXT_SYS_WLANSYSCOEX_CH_CONTROL 0x0000
33 #define ABS_EXT_SYS_WLANSYSCOEX_CH_CONTROL 0xA401BC00UL
34 #define EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE 0x0004
35 #define EXT_SYS_WLANSYSCOEX_CH_SR_INFO_STATUS 0x0040
36 #define EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0 0x008C
37 #define EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_44 0x013C
38 #define EXT_SYS_WLANSYSCOEX_RESET_SHIFT 0
39 
40 /* copied from uccp530_77_registers.h of UCCP toolkit */
41 #define ABS_PMB_WLAN_MAC_CTRL_PULSED_SOFTWARE_RESET 0xA5009A00UL
42 
43 #ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
44 	#define NRF_RADIO_COEX_NODE DT_NODELABEL(nrf70)
45 	static const struct gpio_dt_spec sr_rf_switch_spec =
46 	GPIO_DT_SPEC_GET(NRF_RADIO_COEX_NODE, srrf_switch_gpios);
47 #endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
48 
49 /* PTA registers configuration of Coexistence Hardware */
50 /* Separate antenna configuration, WLAN in 2.4GHz. For BLE protocol. */
51 const uint16_t config_buffer_SEA_ble[] = {
52 	0x0019, 0x00F6, 0x0008, 0x0062, 0x00F5,
53 	0x00F5, 0x0019, 0x0019, 0x0074, 0x0074,
54 	0x0008, 0x01E2, 0x00D5, 0x00D5, 0x01F6,
55 	0x01F6, 0x0061, 0x0061, 0x01E2, 0x0008,
56 	0x0004, 0x0004, 0x0019, 0x0019, 0x0008,
57 	0x0008, 0x00F5, 0x00F5, 0x00D5, 0x00D5,
58 	0x0008, 0x01E2, 0x0051, 0x0051, 0x0074,
59 	0x0074, 0x00F6, 0x0019, 0x0062, 0x0019,
60 	0x00F6, 0x0008, 0x0062, 0x0008, 0x001A
61 };
62 
63 /* Separate antenna configuration, WLAN in 2.4GHz. For non BLE protocol */
64 const uint16_t config_buffer_SEA_non_ble[] = {
65 	0x0019, 0x00F6, 0x0008, 0x0062, 0x00F5,
66 	0x00F5, 0x0061, 0x0061, 0x0074, 0x0074,
67 	0x01E2, 0x01E2, 0x00D5, 0x00D5, 0x01F6,
68 	0x01F6, 0x0061, 0x0061, 0x01E2, 0x01E2,
69 	0x00C4, 0x00C4, 0x0061, 0x0061, 0x0008,
70 	0x0008, 0x00F5, 0x00F5, 0x00D5, 0x00D5,
71 	0x0162, 0x0162, 0x0019, 0x0019, 0x01F6,
72 	0x01F6, 0x00F6, 0x0019, 0x0062, 0x0019,
73 	0x00F6, 0x0008, 0x0062, 0x0008, 0x001A
74 };
75 
76 /* Shared antenna configuration, WLAN in 2.4GHz. */
77 const uint16_t config_buffer_SHA[] = {
78 	0x0019, 0x00F6, 0x0008, 0x00E2, 0x0015,
79 	0x00F5, 0x0019, 0x0019, 0x0004, 0x01F6,
80 	0x0008, 0x01E2, 0x00F5, 0x00F5, 0x01F6,
81 	0x01F6, 0x00E1, 0x00E1, 0x01E2, 0x0008,
82 	0x0004, 0x0004, 0x0019, 0x0019, 0x0008,
83 	0x0008, 0x0015, 0x00F5, 0x00F5, 0x00F5,
84 	0x0008, 0x01E2, 0x00E1, 0x00E1, 0x0004,
85 	0x01F6, 0x00F6, 0x0019, 0x00E2, 0x0019,
86 	0x00F6, 0x0008, 0x00E2, 0x0008, 0x001A
87 };
88 
89 /* Shared/separate antennas, WLAN in 5GHz */
90 const uint16_t config_buffer_5G[] = {
91 	0x0039, 0x0076, 0x0028, 0x0062, 0x0075,
92 	0x0075, 0x0061, 0x0061, 0x0074, 0x0074,
93 	0x0060, 0x0060, 0x0075, 0x0075, 0x0064,
94 	0x0064, 0x0071, 0x0071, 0x0060, 0x0060,
95 	0x0064, 0x0064, 0x0061, 0x0061, 0x0060,
96 	0x0060, 0x0075, 0x0075, 0x0075, 0x0075,
97 	0x0060, 0x0060, 0x0071, 0x0071, 0x0074,
98 	0x0074, 0x0076, 0x0039, 0x0062, 0x0039,
99 	0x0076, 0x0028, 0x0062, 0x0028, 0x003A
100 };
101 
102 /* non-PTA register configuration of coexistence hardware */
103 /* Shared antenna */
104 const uint32_t ch_config_sha[] = {
105 	0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
106 	0x00000000, 0x00000021, 0x000002ca, 0x00000050, 0x00000000,
107 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
108 	0x00000000
109 };
110 
111 /* Separate antennas. For BLE protocol. */
112 const uint32_t ch_config_sep_ble[] = {
113 	0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
114 	0x00000000, 0x00000021, 0x000002ca, 0x00000055, 0x00000000,
115 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
116 	0x00000000
117 };
118 
119 /* Separate antennas. For non BLE protocol. */
120 const uint32_t ch_config_sep_non_ble[] = {
121 	0x00000028, 0x00000000, 0x001e1023, 0x00000000, 0x00000000,
122 	0x00000000, 0x00000021, 0x000002ca, 0x00000055, 0x00000000,
123 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
124 	0x00000000
125 };
126 
nrf_wifi_coex_config_non_pta(bool separate_antennas,bool is_sr_protocol_ble)127 int nrf_wifi_coex_config_non_pta(bool separate_antennas, bool is_sr_protocol_ble)
128 {
129 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
130 	struct coex_ch_configuration params  = { 0 };
131 	const uint32_t *config_buffer_ptr = NULL;
132 	uint32_t start_offset = 0;
133 	uint32_t num_reg_to_config = 1;
134 	uint32_t cmd_len, index;
135 
136 	/* Offset from the base address of CH */
137 	start_offset = ((EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE -
138 	EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
139 	/* Number of registers to be configured */
140 	num_reg_to_config = ((EXT_SYS_WLANSYSCOEX_CH_SR_INFO_STATUS -
141 	EXT_SYS_WLANSYSCOEX_CH_TIME_REFERENCE) >> 2) + 1;
142 
143 	if (separate_antennas) {
144 		if (is_sr_protocol_ble) {
145 			config_buffer_ptr = ch_config_sep_ble;
146 		} else {
147 			config_buffer_ptr = ch_config_sep_non_ble;
148 		}
149 	} else {
150 		config_buffer_ptr = ch_config_sha;
151 	}
152 
153 	params.message_id = HW_CONFIGURATION;
154 	params.num_reg_to_config = num_reg_to_config;
155 	params.hw_to_config = COEX_HARDWARE;
156 	params.hw_block_base_addr = CH_BASE_ADDRESS;
157 
158 	for (index = 0; index < num_reg_to_config; index++) {
159 		params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
160 			(*(config_buffer_ptr + index));
161 		start_offset++;
162 	}
163 
164 	cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
165 	status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
166 					   (void *)(&params), cmd_len);
167 	if (status != NRF_WIFI_STATUS_SUCCESS) {
168 		return -1;
169 	}
170 
171 	return 0;
172 }
173 
nrf_wifi_coex_config_pta(enum nrf_wifi_pta_wlan_op_band wlan_band,bool separate_antennas,bool is_sr_protocol_ble)174 int nrf_wifi_coex_config_pta(enum nrf_wifi_pta_wlan_op_band wlan_band, bool separate_antennas,
175 	bool is_sr_protocol_ble)
176 {
177 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
178 	struct coex_ch_configuration params  = { 0 };
179 	const uint16_t *config_buffer_ptr = NULL;
180 	uint32_t start_offset = 0;
181 	uint32_t num_reg_to_config = 1;
182 	uint32_t cmd_len, index;
183 
184 	/* common for both SHA and SEA */
185 	/* Indicates offset from the base address of CH */
186 	start_offset = ((EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0 -
187 	EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
188 	/* Number of contiguous registers to be configured starting from base+offset */
189 	num_reg_to_config = ((EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_44 -
190 	EXT_SYS_WLANSYSCOEX_CH_NO_WINDOW_LOOKUP_0) >> 2) + 1;
191 
192 	if (wlan_band == NRF_WIFI_PTA_WLAN_OP_BAND_2_4_GHZ) {
193 		/* WLAN operating in 2.4GHz */
194 		if (separate_antennas) {
195 			/* separate antennas configuration */
196 			if (is_sr_protocol_ble) {
197 				config_buffer_ptr = config_buffer_SEA_ble;
198 			} else {
199 				config_buffer_ptr = config_buffer_SEA_non_ble;
200 			}
201 		} else {
202 			/* Shared antenna configuration */
203 			config_buffer_ptr = config_buffer_SHA;
204 		}
205 	} else if (wlan_band == NRF_WIFI_PTA_WLAN_OP_BAND_5_GHZ) {
206 		/* WLAN operating in 5GHz */
207 		config_buffer_ptr = config_buffer_5G;
208 	} else {
209 		return -EINVAL;
210 	}
211 
212 	params.message_id = HW_CONFIGURATION;
213 	params.num_reg_to_config = num_reg_to_config;
214 	params.hw_to_config = COEX_HARDWARE;
215 	params.hw_block_base_addr = CH_BASE_ADDRESS;
216 
217 	for (index = 0; index < num_reg_to_config; index++) {
218 		params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
219 			(*(config_buffer_ptr+index));
220 		start_offset++;
221 	}
222 
223 	cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
224 	status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
225 					   (void *)(&params), cmd_len);
226 	if (status != NRF_WIFI_STATUS_SUCCESS) {
227 		return -1;
228 	}
229 
230 	return 0;
231 }
232 #ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
nrf_wifi_config_sr_switch(bool separate_antennas)233 int nrf_wifi_config_sr_switch(bool separate_antennas)
234 {
235 	int ret;
236 
237 	if (!device_is_ready(sr_rf_switch_spec.port)) {
238 		LOG_ERR("Unable to open GPIO device");
239 		return -ENODEV;
240 	}
241 
242 	ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_OUTPUT);
243 	if (ret < 0) {
244 		LOG_ERR("Unable to configure GPIO device");
245 		return -1;
246 	}
247 
248 	if (separate_antennas) {
249 		gpio_pin_set_dt(&sr_rf_switch_spec, 0x0);
250 	} else {
251 		gpio_pin_set_dt(&sr_rf_switch_spec, 0x1);
252 	}
253 
254 	return 0;
255 }
256 #endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
257 
nrf_wifi_coex_hw_reset(void)258 int nrf_wifi_coex_hw_reset(void)
259 {
260 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
261 	struct coex_ch_configuration params  = { 0 };
262 	uint32_t num_reg_to_config = 1;
263 	uint32_t start_offset = 0;
264 	uint32_t index = 0;
265 	uint32_t coex_hw_reset = 1;
266 	uint32_t cmd_len;
267 
268 	/* reset CH */
269 	params.message_id = HW_CONFIGURATION;
270 	params.num_reg_to_config = num_reg_to_config;
271 	params.hw_to_config = COEX_HARDWARE;
272 	params.hw_block_base_addr = CH_BASE_ADDRESS;
273 
274 	start_offset = ((EXT_SYS_WLANSYSCOEX_CH_CONTROL - EXT_SYS_WLANSYSCOEX_CH_CONTROL) >> 2);
275 	params.configbuf[index] = (start_offset << COEX_REG_CFG_OFFSET_SHIFT) |
276 	(coex_hw_reset << EXT_SYS_WLANSYSCOEX_RESET_SHIFT);
277 
278 	cmd_len = (COEX_CONFIG_FIXED_PARAMS + num_reg_to_config) * sizeof(uint32_t);
279 
280 	status = nrf_wifi_fmac_conf_srcoex(rpu_ctx->rpu_ctx,
281 				(void *)(&params), cmd_len);
282 
283 	if (status != NRF_WIFI_STATUS_SUCCESS) {
284 		LOG_ERR("CH reset configuration failed");
285 		return -1;
286 	}
287 
288 	return 0;
289 }
290 
291 #ifdef CONFIG_NRF70_SR_COEX_RF_SWITCH
sr_gpio_config(void)292 int sr_gpio_config(void)
293 {
294 	int ret;
295 
296 	if (!device_is_ready(sr_rf_switch_spec.port)) {
297 		return -ENODEV;
298 	}
299 
300 	ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_OUTPUT);
301 	if (ret) {
302 		LOG_ERR("SR GPIO configuration failed %d", ret);
303 	}
304 
305 	return ret;
306 }
307 
sr_gpio_remove(void)308 int sr_gpio_remove(void)
309 {
310 	int ret;
311 
312 	ret = gpio_pin_configure_dt(&sr_rf_switch_spec, GPIO_DISCONNECTED);
313 	if (ret) {
314 		LOG_ERR("SR GPIO remove failed %d", ret);
315 	}
316 
317 	return ret;
318 }
319 
sr_ant_switch(unsigned int ant_switch)320 int sr_ant_switch(unsigned int ant_switch)
321 {
322 	int ret;
323 
324 	ret = gpio_pin_set_dt(&sr_rf_switch_spec, ant_switch & 0x1);
325 	if (ret) {
326 		LOG_ERR("SR GPIO set failed %d", ret);
327 	}
328 
329 	return ret;
330 }
331 #endif /* CONFIG_NRF70_SR_COEX_RF_SWITCH */
332