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 *)(¶ms), 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 *)(¶ms), 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 *)(¶ms), 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