1 /*
2  * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "esp_coexist.h"
8 #include "private/esp_coexist_internal.h"
9 #include "soc/soc_caps.h"
10 
11 #if CONFIG_EXTERNAL_COEX_ENABLE
12 #include "esp_log.h"
13 #include "driver/gpio.h"
14 #include "esp_rom_gpio.h"
15 #include "hal/gpio_hal.h"
16 #include "esp_attr.h"
17 #include "esp_private/gpio.h"
18 #endif
19 
20 #if SOC_MODEM_CLOCK_IS_INDEPENDENT
21 #include "esp_private/esp_modem_clock.h"
22 #endif
23 
24 #if SOC_EXTERNAL_COEX_ADVANCE
25 #define EXTERNAL_COEX_SIGNAL_I0_IDX           EXTERN_ACTIVE_I_IDX
26 #define EXTERNAL_COEX_SIGNAL_I1_IDX           EXTERN_PRIORITY_I_IDX
27 #define EXTERNAL_COEX_SIGNAL_O0_IDX           EXTERN_ACTIVE_O_IDX
28 #define EXTERNAL_COEX_SIGNAL_O1_IDX           EXTERN_PRIORITY_O_IDX
29 #else
30 #define EXTERNAL_COEX_SIGNAL_I0_IDX           GPIO_BT_ACTIVE_IDX
31 #define EXTERNAL_COEX_SIGNAL_I1_IDX           GPIO_BT_PRIORITY_IDX
32 #define EXTERNAL_COEX_SIGNAL_O0_IDX           GPIO_WLAN_ACTIVE_IDX
33 #endif
34 
35 #if SOC_EXTERNAL_COEX_LEADER_TX_LINE
36 #define EXTERNAL_COEX_SIGNAL_O1_TXLINE_IDX    BB_DIAG9_IDX
37 #endif
38 
esp_coex_version_get(void)39 const char *esp_coex_version_get(void)
40 {
41     return coex_version_get();
42 }
43 
esp_coex_preference_set(esp_coex_prefer_t prefer)44 esp_err_t esp_coex_preference_set(esp_coex_prefer_t prefer)
45 {
46     return coex_preference_set((coex_prefer_t)prefer);
47 }
48 
49 #if CONFIG_EXTERNAL_COEX_ENABLE
50 #define GPIO_PIN_REG(a) (GPIO_PIN0_REG + a * 0x04)
51 static const char *TAG = "external_coex";
52 
53 static esp_external_coex_advance_t g_external_coex_params = { EXTERNAL_COEX_LEADER_ROLE, 0, true };
54 
esp_external_coex_set_work_mode(esp_extern_coex_work_mode_t work_mode)55 esp_err_t esp_external_coex_set_work_mode(esp_extern_coex_work_mode_t work_mode)
56 {
57 #if !SOC_EXTERNAL_COEX_ADVANCE
58     if(work_mode != EXTERNAL_COEX_LEADER_ROLE)
59     {
60         return ESP_ERR_INVALID_ARG;
61     }
62 #endif
63     g_external_coex_params.work_mode = work_mode;
64     return ESP_OK;
65 }
66 
is_legal_external_coex_gpio(external_coex_wire_t wire_type,esp_external_coex_gpio_set_t gpio_pin)67 bool is_legal_external_coex_gpio(external_coex_wire_t wire_type, esp_external_coex_gpio_set_t gpio_pin)
68 {
69     switch (wire_type)
70     {
71         case EXTERN_COEX_WIRE_4:
72         {
73             if(!GPIO_IS_VALID_GPIO(gpio_pin.tx_line)
74                 || gpio_pin.tx_line == gpio_pin.priority || gpio_pin.tx_line == gpio_pin.grant || gpio_pin.tx_line == gpio_pin.request) {
75                 return false;
76             }
77         }
78         __attribute__((fallthrough));
79         case EXTERN_COEX_WIRE_3:
80         {
81             if(!GPIO_IS_VALID_GPIO(gpio_pin.priority) || gpio_pin.priority == gpio_pin.grant || gpio_pin.priority == gpio_pin.request) {
82                 return false;
83             }
84         }
85         __attribute__((fallthrough));
86         case EXTERN_COEX_WIRE_2:
87         {
88             if(!GPIO_IS_VALID_GPIO(gpio_pin.grant) || gpio_pin.grant == gpio_pin.request) {
89                 return false;
90             }
91         }
92         __attribute__((fallthrough));
93         case EXTERN_COEX_WIRE_1:
94         {
95             if(!GPIO_IS_VALID_GPIO(gpio_pin.request)) {
96                 return false;
97             }
98             break;
99         }
100         default:
101             return false;
102     }
103     return true;
104 }
105 
106 #if SOC_EXTERNAL_COEX_ADVANCE
esp_external_coex_set_gpio_pin(esp_external_coex_gpio_set_t * gpio_pin,external_coex_wire_t wire_type,uint32_t request,uint32_t priority,uint32_t grant)107 esp_err_t esp_external_coex_set_gpio_pin(esp_external_coex_gpio_set_t *gpio_pin, external_coex_wire_t wire_type, uint32_t request, uint32_t priority, uint32_t grant)
108 {
109     switch (wire_type) {
110         case EXTERN_COEX_WIRE_3:
111             gpio_pin->priority  = priority;
112             __attribute__((fallthrough));
113         case EXTERN_COEX_WIRE_2:
114             gpio_pin->grant = grant;
115             __attribute__((fallthrough));
116         case EXTERN_COEX_WIRE_1:
117         {
118             gpio_pin->request  = request;
119             break;
120         }
121         default:
122         {
123             gpio_pin->request  = request;
124             gpio_pin->priority  = priority;
125             gpio_pin->grant = grant;
126             break;
127         }
128     }
129     return ESP_OK;
130 }
131 
esp_external_coex_set_grant_delay(uint8_t delay_us)132 esp_err_t esp_external_coex_set_grant_delay(uint8_t delay_us)
133 {
134     g_external_coex_params.delay_us = delay_us;
135     return ESP_OK;
136 }
137 
esp_external_coex_set_validate_high(bool is_high_valid)138 esp_err_t esp_external_coex_set_validate_high(bool is_high_valid)
139 {
140     g_external_coex_params.is_high_valid = is_high_valid;
141     return ESP_OK;
142 }
143 
esp_external_coex_leader_role_set_gpio_pin(external_coex_wire_t wire_type,uint32_t request,uint32_t priority,uint32_t grant)144 esp_err_t esp_external_coex_leader_role_set_gpio_pin(external_coex_wire_t wire_type, uint32_t request, uint32_t priority, uint32_t grant)
145 {
146     esp_external_coex_set_work_mode(EXTERNAL_COEX_LEADER_ROLE);
147     esp_external_coex_gpio_set_t gpio_pin;
148     esp_external_coex_set_gpio_pin(&gpio_pin, wire_type, request, priority, grant);
149     return esp_enable_extern_coex_gpio_pin(wire_type, gpio_pin);
150 }
151 
esp_external_coex_follower_role_set_gpio_pin(external_coex_wire_t wire_type,uint32_t request,uint32_t priority,uint32_t grant)152 esp_err_t esp_external_coex_follower_role_set_gpio_pin(external_coex_wire_t wire_type, uint32_t request, uint32_t priority, uint32_t grant)
153 {
154     esp_external_coex_set_work_mode(EXTERNAL_COEX_FOLLOWER_ROLE);
155     esp_external_coex_gpio_set_t gpio_pin;
156     esp_external_coex_set_gpio_pin(&gpio_pin, wire_type, request, priority, grant);
157     return esp_enable_extern_coex_gpio_pin(wire_type, gpio_pin);
158 }
159 #endif /* SOC_EXTERNAL_COEX_ADVANCE */
160 
esp_enable_extern_coex_gpio_pin(external_coex_wire_t wire_type,esp_external_coex_gpio_set_t gpio_pin)161 esp_err_t esp_enable_extern_coex_gpio_pin(external_coex_wire_t wire_type, esp_external_coex_gpio_set_t gpio_pin)
162 {
163     if(false == is_legal_external_coex_gpio(wire_type, gpio_pin))
164     {
165         ESP_LOGE(TAG, "Configure external coex with unexpected gpio pin!!!\n");
166         return ESP_ERR_INVALID_ARG;
167     }
168     esp_coex_external_set_wire_type(wire_type);
169 
170     if(EXTERNAL_COEX_LEADER_ROLE == g_external_coex_params.work_mode) {
171         switch (wire_type)
172         {
173 #if SOC_EXTERNAL_COEX_LEADER_TX_LINE
174             case EXTERN_COEX_WIRE_4:
175             {
176                 esp_coex_external_set_txline(true);
177                 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_pin.tx_line], PIN_FUNC_GPIO);
178                 gpio_set_direction(gpio_pin.tx_line, GPIO_MODE_OUTPUT);
179                 REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(gpio_pin.tx_line));
180                 esp_rom_gpio_connect_out_signal(gpio_pin.tx_line, EXTERNAL_COEX_SIGNAL_O1_TXLINE_IDX, false, false);
181             }
182             __attribute__((fallthrough));
183 #endif
184             case EXTERN_COEX_WIRE_3:
185             {
186                 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_pin.priority], PIN_FUNC_GPIO);
187                 gpio_set_direction(gpio_pin.priority, GPIO_MODE_INPUT);
188                 esp_rom_gpio_connect_in_signal(gpio_pin.priority, EXTERNAL_COEX_SIGNAL_I1_IDX, false);
189                 REG_SET_FIELD(GPIO_PIN_REG(gpio_pin.priority), GPIO_PIN1_SYNC1_BYPASS, 2);
190                 REG_SET_FIELD(GPIO_PIN_REG(gpio_pin.priority), GPIO_PIN1_SYNC2_BYPASS, 2);
191             }
192             __attribute__((fallthrough));
193             case EXTERN_COEX_WIRE_2:
194             {
195                 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_pin.grant], PIN_FUNC_GPIO);
196                 gpio_set_direction(gpio_pin.grant, GPIO_MODE_OUTPUT);
197                 REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(gpio_pin.grant));
198                 esp_rom_gpio_connect_out_signal(gpio_pin.grant, EXTERNAL_COEX_SIGNAL_O0_IDX, false, false);
199             }
200             __attribute__((fallthrough));
201             case EXTERN_COEX_WIRE_1:
202             {
203                 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_pin.request], PIN_FUNC_GPIO);
204                 gpio_set_direction(gpio_pin.request, GPIO_MODE_INPUT);
205                 esp_rom_gpio_connect_in_signal(gpio_pin.request, EXTERNAL_COEX_SIGNAL_I0_IDX, false);
206                 REG_SET_FIELD(GPIO_PIN_REG(gpio_pin.request), GPIO_PIN1_SYNC1_BYPASS, 2);
207                 REG_SET_FIELD(GPIO_PIN_REG(gpio_pin.request), GPIO_PIN1_SYNC2_BYPASS, 2);
208                 break;
209             }
210             default:
211             {
212                 return ESP_FAIL;
213             }
214         }
215     } else if(EXTERNAL_COEX_FOLLOWER_ROLE == g_external_coex_params.work_mode) {
216 #if SOC_EXTERNAL_COEX_ADVANCE
217         switch (wire_type)
218         {
219             case EXTERN_COEX_WIRE_4:
220             {
221                 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_pin.tx_line], PIN_FUNC_GPIO);
222                 gpio_set_direction(gpio_pin.tx_line, GPIO_MODE_INPUT);
223                 esp_rom_gpio_connect_in_signal(gpio_pin.tx_line, EXTERNAL_COEX_SIGNAL_I1_IDX, false);
224                 REG_SET_FIELD(GPIO_PIN_REG(gpio_pin.tx_line), GPIO_PIN1_SYNC1_BYPASS, 2);
225                 REG_SET_FIELD(GPIO_PIN_REG(gpio_pin.tx_line), GPIO_PIN1_SYNC2_BYPASS, 2);
226             }
227             __attribute__((fallthrough));
228             case EXTERN_COEX_WIRE_3:
229             {
230                 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_pin.priority], PIN_FUNC_GPIO);
231                 gpio_set_direction(gpio_pin.priority, GPIO_MODE_OUTPUT);
232                 REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(gpio_pin.priority));
233                 esp_rom_gpio_connect_out_signal(gpio_pin.priority, EXTERNAL_COEX_SIGNAL_O1_IDX, false, false);
234             }
235             __attribute__((fallthrough));
236             case EXTERN_COEX_WIRE_2:
237             {
238                 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_pin.grant], PIN_FUNC_GPIO);
239                 gpio_set_direction(gpio_pin.grant, GPIO_MODE_INPUT);
240                 esp_rom_gpio_connect_in_signal(gpio_pin.grant, EXTERNAL_COEX_SIGNAL_I0_IDX, false);
241                 REG_SET_FIELD(GPIO_PIN_REG(gpio_pin.grant), GPIO_PIN1_SYNC1_BYPASS, 2);
242                 REG_SET_FIELD(GPIO_PIN_REG(gpio_pin.grant), GPIO_PIN1_SYNC2_BYPASS, 2);
243             }
244             __attribute__((fallthrough));
245             case EXTERN_COEX_WIRE_1:
246             {
247                 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_pin.request], PIN_FUNC_GPIO);
248                 gpio_set_direction(gpio_pin.request, GPIO_MODE_OUTPUT);
249                 REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(gpio_pin.request));
250                 esp_rom_gpio_connect_out_signal(gpio_pin.request, EXTERNAL_COEX_SIGNAL_O0_IDX, false, false);
251                 break;
252             }
253             default:
254             {
255                 return ESP_FAIL;
256             }
257         }
258 #else
259         return ESP_ERR_INVALID_ARG;
260 #endif /* SOC_EXTERNAL_COEX_ADVANCE */
261     }
262 #if SOC_MODEM_CLOCK_IS_INDEPENDENT
263     modem_clock_module_enable(PERIPH_COEX_MODULE);
264 #endif
265 #if SOC_EXTERNAL_COEX_ADVANCE
266     esp_coex_external_params(g_external_coex_params, 0, 0);
267 #endif
268     esp_err_t ret = esp_coex_external_set(EXTERN_COEX_PTI_MID, EXTERN_COEX_PTI_MID, EXTERN_COEX_PTI_HIGH);
269 #if SOC_MODEM_CLOCK_IS_INDEPENDENT
270     modem_clock_module_disable(PERIPH_COEX_MODULE);
271 #endif
272     if (ESP_OK != ret) {
273         return ESP_FAIL;
274     }
275     return ESP_OK;
276 }
277 
esp_disable_extern_coex_gpio_pin(void)278 esp_err_t esp_disable_extern_coex_gpio_pin(void)
279 {
280     esp_coex_external_stop();
281 
282     return ESP_OK;
283 }
284 #endif /* External Coex */
285 
286 #if CONFIG_ESP_COEX_SW_COEXIST_ENABLE && CONFIG_SOC_IEEE802154_SUPPORTED
esp_coex_wifi_i154_enable(void)287 esp_err_t esp_coex_wifi_i154_enable(void)
288 {
289     // TODO: Add a scheme for wifi and 154 coex.
290     // Remove this function if FCC-50 closes.
291     coex_enable();
292     coex_schm_status_bit_set(1, 1);
293     return ESP_OK;
294 }
295 #endif
296