1 | /* |
2 | * Copyright (c) 2008-2011 Atheros Communications Inc. |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include <linux/export.h> |
18 | #include "hw.h" |
19 | #include "hw-ops.h" |
20 | #include "ar9003_phy.h" |
21 | #include "ar9003_mci.h" |
22 | #include "ar9003_aic.h" |
23 | |
24 | static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah) |
25 | { |
26 | REG_RMW_FIELD(ah, AR_MCI_COMMAND2, |
27 | AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1); |
28 | udelay(1); |
29 | REG_RMW_FIELD(ah, AR_MCI_COMMAND2, |
30 | AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 0); |
31 | } |
32 | |
33 | static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address, |
34 | u32 bit_position, int time_out) |
35 | { |
36 | struct ath_common *common = ath9k_hw_common(ah); |
37 | |
38 | while (time_out) { |
39 | if (!(REG_READ(ah, address) & bit_position)) { |
40 | udelay(10); |
41 | time_out -= 10; |
42 | |
43 | if (time_out < 0) |
44 | break; |
45 | else |
46 | continue; |
47 | } |
48 | REG_WRITE(ah, address, bit_position); |
49 | |
50 | if (address != AR_MCI_INTERRUPT_RX_MSG_RAW) |
51 | break; |
52 | |
53 | if (bit_position & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) |
54 | ar9003_mci_reset_req_wakeup(ah); |
55 | |
56 | if (bit_position & (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING | |
57 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) |
58 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, |
59 | AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); |
60 | |
61 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_RX_MSG); |
62 | break; |
63 | } |
64 | |
65 | if (time_out <= 0) { |
66 | ath_dbg(common, MCI, |
67 | "MCI Wait for Reg 0x%08x = 0x%08x timeout\n" , |
68 | address, bit_position); |
69 | ath_dbg(common, MCI, |
70 | "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x\n" , |
71 | REG_READ(ah, AR_MCI_INTERRUPT_RAW), |
72 | REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); |
73 | time_out = 0; |
74 | } |
75 | |
76 | return time_out; |
77 | } |
78 | |
79 | static void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done) |
80 | { |
81 | u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00}; |
82 | |
83 | ar9003_mci_send_message(ah, header: MCI_REMOTE_RESET, flag: 0, payload, len: 16, |
84 | wait_done, check_bt: false); |
85 | udelay(5); |
86 | } |
87 | |
88 | static void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done) |
89 | { |
90 | u32 payload = 0x00000000; |
91 | |
92 | ar9003_mci_send_message(ah, header: MCI_LNA_TRANS, flag: 0, payload: &payload, len: 1, |
93 | wait_done, check_bt: false); |
94 | } |
95 | |
96 | static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done) |
97 | { |
98 | ar9003_mci_send_message(ah, header: MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP, |
99 | NULL, len: 0, wait_done, check_bt: false); |
100 | udelay(5); |
101 | } |
102 | |
103 | static void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done) |
104 | { |
105 | ar9003_mci_send_message(ah, header: MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP, |
106 | NULL, len: 0, wait_done, check_bt: false); |
107 | } |
108 | |
109 | static void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done) |
110 | { |
111 | u32 payload = 0x70000000; |
112 | |
113 | ar9003_mci_send_message(ah, header: MCI_LNA_TAKE, flag: 0, payload: &payload, len: 1, |
114 | wait_done, check_bt: false); |
115 | } |
116 | |
117 | static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done) |
118 | { |
119 | ar9003_mci_send_message(ah, header: MCI_SYS_SLEEPING, |
120 | MCI_FLAG_DISABLE_TIMESTAMP, |
121 | NULL, len: 0, wait_done, check_bt: false); |
122 | } |
123 | |
124 | static void ar9003_mci_send_coex_version_query(struct ath_hw *ah, |
125 | bool wait_done) |
126 | { |
127 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
128 | u32 payload[4] = {0, 0, 0, 0}; |
129 | |
130 | if (mci->bt_version_known || |
131 | (mci->bt_state == MCI_BT_SLEEP)) |
132 | return; |
133 | |
134 | MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, |
135 | MCI_GPM_COEX_VERSION_QUERY); |
136 | ar9003_mci_send_message(ah, header: MCI_GPM, flag: 0, payload, len: 16, wait_done, check_bt: true); |
137 | } |
138 | |
139 | static void ar9003_mci_send_coex_version_response(struct ath_hw *ah, |
140 | bool wait_done) |
141 | { |
142 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
143 | u32 payload[4] = {0, 0, 0, 0}; |
144 | |
145 | MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, |
146 | MCI_GPM_COEX_VERSION_RESPONSE); |
147 | *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) = |
148 | mci->wlan_ver_major; |
149 | *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) = |
150 | mci->wlan_ver_minor; |
151 | ar9003_mci_send_message(ah, header: MCI_GPM, flag: 0, payload, len: 16, wait_done, check_bt: true); |
152 | } |
153 | |
154 | static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah, |
155 | bool wait_done) |
156 | { |
157 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
158 | u32 *payload = &mci->wlan_channels[0]; |
159 | |
160 | if (!mci->wlan_channels_update || |
161 | (mci->bt_state == MCI_BT_SLEEP)) |
162 | return; |
163 | |
164 | MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, |
165 | MCI_GPM_COEX_WLAN_CHANNELS); |
166 | ar9003_mci_send_message(ah, header: MCI_GPM, flag: 0, payload, len: 16, wait_done, check_bt: true); |
167 | MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff); |
168 | } |
169 | |
170 | static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, |
171 | bool wait_done, u8 query_type) |
172 | { |
173 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
174 | u32 payload[4] = {0, 0, 0, 0}; |
175 | bool query_btinfo; |
176 | |
177 | if (mci->bt_state == MCI_BT_SLEEP) |
178 | return; |
179 | |
180 | query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO | |
181 | MCI_GPM_COEX_QUERY_BT_TOPOLOGY)); |
182 | MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, |
183 | MCI_GPM_COEX_STATUS_QUERY); |
184 | |
185 | *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type; |
186 | |
187 | /* |
188 | * If bt_status_query message is not sent successfully, |
189 | * then need_flush_btinfo should be set again. |
190 | */ |
191 | if (!ar9003_mci_send_message(ah, header: MCI_GPM, flag: 0, payload, len: 16, |
192 | wait_done, check_bt: true)) { |
193 | if (query_btinfo) |
194 | mci->need_flush_btinfo = true; |
195 | } |
196 | |
197 | if (query_btinfo) |
198 | mci->query_bt = false; |
199 | } |
200 | |
201 | static void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, |
202 | bool wait_done) |
203 | { |
204 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
205 | u32 payload[4] = {0, 0, 0, 0}; |
206 | |
207 | MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, |
208 | MCI_GPM_COEX_HALT_BT_GPM); |
209 | |
210 | if (halt) { |
211 | mci->query_bt = true; |
212 | /* Send next unhalt no matter halt sent or not */ |
213 | mci->unhalt_bt_gpm = true; |
214 | mci->need_flush_btinfo = true; |
215 | *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = |
216 | MCI_GPM_COEX_BT_GPM_HALT; |
217 | } else |
218 | *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = |
219 | MCI_GPM_COEX_BT_GPM_UNHALT; |
220 | |
221 | ar9003_mci_send_message(ah, header: MCI_GPM, flag: 0, payload, len: 16, wait_done, check_bt: true); |
222 | } |
223 | |
224 | static void ar9003_mci_prep_interface(struct ath_hw *ah) |
225 | { |
226 | struct ath_common *common = ath9k_hw_common(ah); |
227 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
228 | u32 saved_mci_int_en; |
229 | u32 mci_timeout = 150; |
230 | |
231 | mci->bt_state = MCI_BT_SLEEP; |
232 | saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); |
233 | |
234 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); |
235 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, |
236 | REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); |
237 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, |
238 | REG_READ(ah, AR_MCI_INTERRUPT_RAW)); |
239 | |
240 | ar9003_mci_remote_reset(ah, wait_done: true); |
241 | ar9003_mci_send_req_wake(ah, wait_done: true); |
242 | |
243 | if (!ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, |
244 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, time_out: 500)) |
245 | goto clear_redunt; |
246 | |
247 | mci->bt_state = MCI_BT_AWAKE; |
248 | |
249 | /* |
250 | * we don't need to send more remote_reset at this moment. |
251 | * If BT receive first remote_reset, then BT HW will |
252 | * be cleaned up and will be able to receive req_wake |
253 | * and BT HW will respond sys_waking. |
254 | * In this case, WLAN will receive BT's HW sys_waking. |
255 | * Otherwise, if BT SW missed initial remote_reset, |
256 | * that remote_reset will still clean up BT MCI RX, |
257 | * and the req_wake will wake BT up, |
258 | * and BT SW will respond this req_wake with a remote_reset and |
259 | * sys_waking. In this case, WLAN will receive BT's SW |
260 | * sys_waking. In either case, BT's RX is cleaned up. So we |
261 | * don't need to reply BT's remote_reset now, if any. |
262 | * Similarly, if in any case, WLAN can receive BT's sys_waking, |
263 | * that means WLAN's RX is also fine. |
264 | */ |
265 | ar9003_mci_send_sys_waking(ah, wait_done: true); |
266 | udelay(10); |
267 | |
268 | /* |
269 | * Set BT priority interrupt value to be 0xff to |
270 | * avoid having too many BT PRIORITY interrupts. |
271 | */ |
272 | REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF); |
273 | REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF); |
274 | REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF); |
275 | REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF); |
276 | REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF); |
277 | |
278 | /* |
279 | * A contention reset will be received after send out |
280 | * sys_waking. Also BT priority interrupt bits will be set. |
281 | * Clear those bits before the next step. |
282 | */ |
283 | |
284 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, |
285 | AR_MCI_INTERRUPT_RX_MSG_CONT_RST); |
286 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI); |
287 | |
288 | if (mci->is_2g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { |
289 | ar9003_mci_send_lna_transfer(ah, wait_done: true); |
290 | udelay(5); |
291 | } |
292 | |
293 | if (mci->is_2g && !mci->update_2g5g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { |
294 | if (ar9003_mci_wait_for_interrupt(ah, |
295 | AR_MCI_INTERRUPT_RX_MSG_RAW, |
296 | AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, |
297 | time_out: mci_timeout)) |
298 | ath_dbg(common, MCI, |
299 | "MCI WLAN has control over the LNA & BT obeys it\n" ); |
300 | else |
301 | ath_dbg(common, MCI, |
302 | "MCI BT didn't respond to LNA_TRANS\n" ); |
303 | } |
304 | |
305 | clear_redunt: |
306 | /* Clear the extra redundant SYS_WAKING from BT */ |
307 | if ((mci->bt_state == MCI_BT_AWAKE) && |
308 | (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, |
309 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) && |
310 | (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, |
311 | AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) { |
312 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, |
313 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING); |
314 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, |
315 | AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); |
316 | } |
317 | |
318 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); |
319 | } |
320 | |
321 | void ar9003_mci_set_full_sleep(struct ath_hw *ah) |
322 | { |
323 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
324 | |
325 | if (ar9003_mci_state(ah, state_type: MCI_STATE_ENABLE) && |
326 | (mci->bt_state != MCI_BT_SLEEP) && |
327 | !mci->halted_bt_gpm) { |
328 | ar9003_mci_send_coex_halt_bt_gpm(ah, halt: true, wait_done: true); |
329 | } |
330 | |
331 | mci->ready = false; |
332 | } |
333 | |
334 | static void ar9003_mci_disable_interrupt(struct ath_hw *ah) |
335 | { |
336 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); |
337 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0); |
338 | } |
339 | |
340 | static void ar9003_mci_enable_interrupt(struct ath_hw *ah) |
341 | { |
342 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT); |
343 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, |
344 | AR_MCI_INTERRUPT_RX_MSG_DEFAULT); |
345 | } |
346 | |
347 | static bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints) |
348 | { |
349 | u32 intr; |
350 | |
351 | intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); |
352 | return ((intr & ints) == ints); |
353 | } |
354 | |
355 | void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, |
356 | u32 *rx_msg_intr) |
357 | { |
358 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
359 | |
360 | *raw_intr = mci->raw_intr; |
361 | *rx_msg_intr = mci->rx_msg_intr; |
362 | |
363 | /* Clean int bits after the values are read. */ |
364 | mci->raw_intr = 0; |
365 | mci->rx_msg_intr = 0; |
366 | } |
367 | EXPORT_SYMBOL(ar9003_mci_get_interrupt); |
368 | |
369 | void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked) |
370 | { |
371 | struct ath_common *common = ath9k_hw_common(ah); |
372 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
373 | u32 raw_intr, rx_msg_intr; |
374 | |
375 | rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); |
376 | raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW); |
377 | |
378 | if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) { |
379 | ath_dbg(common, MCI, |
380 | "MCI gets 0xdeadbeef during int processing\n" ); |
381 | } else { |
382 | mci->rx_msg_intr |= rx_msg_intr; |
383 | mci->raw_intr |= raw_intr; |
384 | *masked |= ATH9K_INT_MCI; |
385 | |
386 | if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) |
387 | mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS); |
388 | |
389 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr); |
390 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr); |
391 | } |
392 | } |
393 | |
394 | static void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g) |
395 | { |
396 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
397 | |
398 | if (!mci->update_2g5g && |
399 | (mci->is_2g != is_2g)) |
400 | mci->update_2g5g = true; |
401 | |
402 | mci->is_2g = is_2g; |
403 | } |
404 | |
405 | static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index) |
406 | { |
407 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
408 | u32 *payload; |
409 | u32 recv_type, offset; |
410 | |
411 | if (msg_index == MCI_GPM_INVALID) |
412 | return false; |
413 | |
414 | offset = msg_index << 4; |
415 | |
416 | payload = (u32 *)(mci->gpm_buf + offset); |
417 | recv_type = MCI_GPM_TYPE(payload); |
418 | |
419 | if (recv_type == MCI_GPM_RSVD_PATTERN) |
420 | return false; |
421 | |
422 | return true; |
423 | } |
424 | |
425 | static void ar9003_mci_observation_set_up(struct ath_hw *ah) |
426 | { |
427 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
428 | |
429 | if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) { |
430 | ath9k_hw_gpio_request_out(ah, gpio: 3, NULL, |
431 | AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); |
432 | ath9k_hw_gpio_request_out(ah, gpio: 2, NULL, |
433 | AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK); |
434 | ath9k_hw_gpio_request_out(ah, gpio: 1, NULL, |
435 | AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); |
436 | ath9k_hw_gpio_request_out(ah, gpio: 0, NULL, |
437 | AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); |
438 | } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) { |
439 | ath9k_hw_gpio_request_out(ah, gpio: 3, NULL, |
440 | AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX); |
441 | ath9k_hw_gpio_request_out(ah, gpio: 2, NULL, |
442 | AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX); |
443 | ath9k_hw_gpio_request_out(ah, gpio: 1, NULL, |
444 | AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); |
445 | ath9k_hw_gpio_request_out(ah, gpio: 0, NULL, |
446 | AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); |
447 | ath9k_hw_gpio_request_out(ah, gpio: 5, NULL, |
448 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
449 | } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) { |
450 | ath9k_hw_gpio_request_out(ah, gpio: 3, NULL, |
451 | AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); |
452 | ath9k_hw_gpio_request_out(ah, gpio: 2, NULL, |
453 | AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); |
454 | ath9k_hw_gpio_request_out(ah, gpio: 1, NULL, |
455 | AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); |
456 | ath9k_hw_gpio_request_out(ah, gpio: 0, NULL, |
457 | AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); |
458 | } else |
459 | return; |
460 | |
461 | REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah), AR_GPIO_JTAG_DISABLE); |
462 | |
463 | REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_DS_JTAG_DISABLE, 1); |
464 | REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_WLAN_UART_INTF_EN, 0); |
465 | REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, ATH_MCI_CONFIG_MCI_OBS_GPIO); |
466 | |
467 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0); |
468 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1); |
469 | REG_WRITE(ah, AR_OBS(ah), 0x4b); |
470 | REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03); |
471 | REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01); |
472 | REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02); |
473 | REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03); |
474 | REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS(ah), |
475 | AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07); |
476 | } |
477 | |
478 | static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done, |
479 | u8 opcode, u32 bt_flags) |
480 | { |
481 | u32 pld[4] = {0, 0, 0, 0}; |
482 | |
483 | MCI_GPM_SET_TYPE_OPCODE(pld, MCI_GPM_COEX_AGENT, |
484 | MCI_GPM_COEX_BT_UPDATE_FLAGS); |
485 | |
486 | *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode; |
487 | *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF; |
488 | *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF; |
489 | *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF; |
490 | *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF; |
491 | |
492 | return ar9003_mci_send_message(ah, header: MCI_GPM, flag: 0, payload: pld, len: 16, |
493 | wait_done, check_bt: true); |
494 | } |
495 | |
496 | static void ar9003_mci_sync_bt_state(struct ath_hw *ah) |
497 | { |
498 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
499 | u32 cur_bt_state; |
500 | |
501 | cur_bt_state = ar9003_mci_state(ah, state_type: MCI_STATE_REMOTE_SLEEP); |
502 | |
503 | if (mci->bt_state != cur_bt_state) |
504 | mci->bt_state = cur_bt_state; |
505 | |
506 | if (mci->bt_state != MCI_BT_SLEEP) { |
507 | |
508 | ar9003_mci_send_coex_version_query(ah, wait_done: true); |
509 | ar9003_mci_send_coex_wlan_channels(ah, wait_done: true); |
510 | |
511 | if (mci->unhalt_bt_gpm == true) |
512 | ar9003_mci_send_coex_halt_bt_gpm(ah, halt: false, wait_done: true); |
513 | } |
514 | } |
515 | |
516 | void ar9003_mci_check_bt(struct ath_hw *ah) |
517 | { |
518 | struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; |
519 | |
520 | if (!mci_hw->ready) |
521 | return; |
522 | |
523 | /* |
524 | * check BT state again to make |
525 | * sure it's not changed. |
526 | */ |
527 | ar9003_mci_sync_bt_state(ah); |
528 | ar9003_mci_2g5g_switch(ah, force: true); |
529 | |
530 | if ((mci_hw->bt_state == MCI_BT_AWAKE) && |
531 | (mci_hw->query_bt == true)) { |
532 | mci_hw->need_flush_btinfo = true; |
533 | } |
534 | } |
535 | |
536 | static void (struct ath_hw *ah, u8 gpm_type, |
537 | u8 gpm_opcode, u32 *p_gpm) |
538 | { |
539 | struct ath_common *common = ath9k_hw_common(ah); |
540 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
541 | u8 *p_data = (u8 *) p_gpm; |
542 | |
543 | if (gpm_type != MCI_GPM_COEX_AGENT) |
544 | return; |
545 | |
546 | switch (gpm_opcode) { |
547 | case MCI_GPM_COEX_VERSION_QUERY: |
548 | ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n" ); |
549 | ar9003_mci_send_coex_version_response(ah, wait_done: true); |
550 | break; |
551 | case MCI_GPM_COEX_VERSION_RESPONSE: |
552 | ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n" ); |
553 | mci->bt_ver_major = |
554 | *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION); |
555 | mci->bt_ver_minor = |
556 | *(p_data + MCI_GPM_COEX_B_MINOR_VERSION); |
557 | mci->bt_version_known = true; |
558 | ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n" , |
559 | mci->bt_ver_major, mci->bt_ver_minor); |
560 | break; |
561 | case MCI_GPM_COEX_STATUS_QUERY: |
562 | ath_dbg(common, MCI, |
563 | "MCI Recv GPM COEX Status Query = 0x%02X\n" , |
564 | *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP)); |
565 | mci->wlan_channels_update = true; |
566 | ar9003_mci_send_coex_wlan_channels(ah, wait_done: true); |
567 | break; |
568 | case MCI_GPM_COEX_BT_PROFILE_INFO: |
569 | mci->query_bt = true; |
570 | ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n" ); |
571 | break; |
572 | case MCI_GPM_COEX_BT_STATUS_UPDATE: |
573 | mci->query_bt = true; |
574 | ath_dbg(common, MCI, |
575 | "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n" , |
576 | *(p_gpm + 3)); |
577 | break; |
578 | default: |
579 | break; |
580 | } |
581 | } |
582 | |
583 | static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, |
584 | u8 gpm_opcode, int time_out) |
585 | { |
586 | struct ath_common *common = ath9k_hw_common(ah); |
587 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
588 | u32 *p_gpm = NULL, more_data; |
589 | u32 offset; |
590 | u8 recv_type = 0, recv_opcode = 0; |
591 | bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); |
592 | |
593 | more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; |
594 | |
595 | while (time_out > 0) { |
596 | if (p_gpm) { |
597 | MCI_GPM_RECYCLE(p_gpm); |
598 | p_gpm = NULL; |
599 | } |
600 | |
601 | if (more_data != MCI_GPM_MORE) |
602 | time_out = ar9003_mci_wait_for_interrupt(ah, |
603 | AR_MCI_INTERRUPT_RX_MSG_RAW, |
604 | AR_MCI_INTERRUPT_RX_MSG_GPM, |
605 | time_out); |
606 | |
607 | if (!time_out) |
608 | break; |
609 | |
610 | offset = ar9003_mci_get_next_gpm_offset(ah, more: &more_data); |
611 | |
612 | if (offset == MCI_GPM_INVALID) |
613 | continue; |
614 | |
615 | p_gpm = (u32 *) (mci->gpm_buf + offset); |
616 | recv_type = MCI_GPM_TYPE(p_gpm); |
617 | recv_opcode = MCI_GPM_OPCODE(p_gpm); |
618 | |
619 | if (MCI_GPM_IS_CAL_TYPE(recv_type)) { |
620 | if (recv_type == gpm_type) { |
621 | if ((gpm_type == MCI_GPM_BT_CAL_DONE) && |
622 | !b_is_bt_cal_done) { |
623 | gpm_type = MCI_GPM_BT_CAL_GRANT; |
624 | continue; |
625 | } |
626 | break; |
627 | } |
628 | } else if ((recv_type == gpm_type) && |
629 | (recv_opcode == gpm_opcode)) |
630 | break; |
631 | |
632 | /* |
633 | * check if it's cal_grant |
634 | * |
635 | * When we're waiting for cal_grant in reset routine, |
636 | * it's possible that BT sends out cal_request at the |
637 | * same time. Since BT's calibration doesn't happen |
638 | * that often, we'll let BT completes calibration then |
639 | * we continue to wait for cal_grant from BT. |
640 | * Orginal: Wait BT_CAL_GRANT. |
641 | * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait |
642 | * BT_CAL_DONE -> Wait BT_CAL_GRANT. |
643 | */ |
644 | |
645 | if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && |
646 | (recv_type == MCI_GPM_BT_CAL_REQ)) { |
647 | |
648 | u32 payload[4] = {0, 0, 0, 0}; |
649 | |
650 | gpm_type = MCI_GPM_BT_CAL_DONE; |
651 | MCI_GPM_SET_CAL_TYPE(payload, |
652 | MCI_GPM_WLAN_CAL_GRANT); |
653 | ar9003_mci_send_message(ah, header: MCI_GPM, flag: 0, payload, len: 16, |
654 | wait_done: false, check_bt: false); |
655 | continue; |
656 | } else { |
657 | ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n" , |
658 | *(p_gpm + 1)); |
659 | ar9003_mci_process_gpm_extra(ah, gpm_type: recv_type, |
660 | gpm_opcode: recv_opcode, p_gpm); |
661 | } |
662 | } |
663 | |
664 | if (p_gpm) { |
665 | MCI_GPM_RECYCLE(p_gpm); |
666 | p_gpm = NULL; |
667 | } |
668 | |
669 | if (time_out <= 0) |
670 | time_out = 0; |
671 | |
672 | while (more_data == MCI_GPM_MORE) { |
673 | offset = ar9003_mci_get_next_gpm_offset(ah, more: &more_data); |
674 | if (offset == MCI_GPM_INVALID) |
675 | break; |
676 | |
677 | p_gpm = (u32 *) (mci->gpm_buf + offset); |
678 | recv_type = MCI_GPM_TYPE(p_gpm); |
679 | recv_opcode = MCI_GPM_OPCODE(p_gpm); |
680 | |
681 | if (!MCI_GPM_IS_CAL_TYPE(recv_type)) |
682 | ar9003_mci_process_gpm_extra(ah, gpm_type: recv_type, |
683 | gpm_opcode: recv_opcode, p_gpm); |
684 | |
685 | MCI_GPM_RECYCLE(p_gpm); |
686 | } |
687 | |
688 | return time_out; |
689 | } |
690 | |
691 | bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan) |
692 | { |
693 | struct ath_common *common = ath9k_hw_common(ah); |
694 | struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; |
695 | u32 payload[4] = {0, 0, 0, 0}; |
696 | |
697 | ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan)); |
698 | |
699 | if (mci_hw->bt_state != MCI_BT_CAL_START) |
700 | return false; |
701 | |
702 | mci_hw->bt_state = MCI_BT_CAL; |
703 | |
704 | /* |
705 | * MCI FIX: disable mci interrupt here. This is to avoid |
706 | * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and |
707 | * lead to mci_intr reentry. |
708 | */ |
709 | ar9003_mci_disable_interrupt(ah); |
710 | |
711 | MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); |
712 | ar9003_mci_send_message(ah, header: MCI_GPM, flag: 0, payload, |
713 | len: 16, wait_done: true, check_bt: false); |
714 | |
715 | /* Wait BT calibration to be completed for 25ms */ |
716 | |
717 | if (ar9003_mci_wait_for_gpm(ah, gpm_type: MCI_GPM_BT_CAL_DONE, |
718 | gpm_opcode: 0, time_out: 25000)) |
719 | ath_dbg(common, MCI, "MCI BT_CAL_DONE received\n" ); |
720 | else |
721 | ath_dbg(common, MCI, |
722 | "MCI BT_CAL_DONE not received\n" ); |
723 | |
724 | mci_hw->bt_state = MCI_BT_AWAKE; |
725 | /* MCI FIX: enable mci interrupt here */ |
726 | ar9003_mci_enable_interrupt(ah); |
727 | |
728 | return true; |
729 | } |
730 | |
731 | int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, |
732 | struct ath9k_hw_cal_data *caldata) |
733 | { |
734 | struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; |
735 | |
736 | if (!mci_hw->ready) |
737 | return 0; |
738 | |
739 | if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP)) |
740 | goto exit; |
741 | |
742 | if (!ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) && |
743 | !ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) |
744 | goto exit; |
745 | |
746 | /* |
747 | * BT is sleeping. Check if BT wakes up during |
748 | * WLAN calibration. If BT wakes up during |
749 | * WLAN calibration, need to go through all |
750 | * message exchanges again and recal. |
751 | */ |
752 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, |
753 | (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | |
754 | AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)); |
755 | |
756 | ar9003_mci_remote_reset(ah, wait_done: true); |
757 | ar9003_mci_send_sys_waking(ah, wait_done: true); |
758 | udelay(1); |
759 | |
760 | if (IS_CHAN_2GHZ(chan)) |
761 | ar9003_mci_send_lna_transfer(ah, wait_done: true); |
762 | |
763 | mci_hw->bt_state = MCI_BT_AWAKE; |
764 | |
765 | REG_CLR_BIT(ah, AR_PHY_TIMING4, |
766 | 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); |
767 | |
768 | if (caldata) { |
769 | clear_bit(nr: TXIQCAL_DONE, addr: &caldata->cal_flags); |
770 | clear_bit(nr: TXCLCAL_DONE, addr: &caldata->cal_flags); |
771 | clear_bit(nr: RTT_DONE, addr: &caldata->cal_flags); |
772 | } |
773 | |
774 | if (!ath9k_hw_init_cal(ah, chan)) |
775 | return -EIO; |
776 | |
777 | REG_SET_BIT(ah, AR_PHY_TIMING4, |
778 | 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); |
779 | |
780 | exit: |
781 | ar9003_mci_enable_interrupt(ah); |
782 | return 0; |
783 | } |
784 | |
785 | static void ar9003_mci_mute_bt(struct ath_hw *ah) |
786 | { |
787 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
788 | |
789 | /* disable all MCI messages */ |
790 | REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); |
791 | REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); |
792 | REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); |
793 | REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); |
794 | REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); |
795 | REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); |
796 | |
797 | /* wait pending HW messages to flush out */ |
798 | udelay(10); |
799 | |
800 | /* |
801 | * Send LNA_TAKE and SYS_SLEEPING when |
802 | * 1. reset not after resuming from full sleep |
803 | * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment |
804 | */ |
805 | if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { |
806 | ar9003_mci_send_lna_take(ah, wait_done: true); |
807 | udelay(5); |
808 | } |
809 | |
810 | ar9003_mci_send_sys_sleeping(ah, wait_done: true); |
811 | } |
812 | |
813 | static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable) |
814 | { |
815 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
816 | u32 thresh; |
817 | |
818 | if (!enable) { |
819 | REG_CLR_BIT(ah, AR_BTCOEX_CTRL, |
820 | AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); |
821 | return; |
822 | } |
823 | REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, AR_MCI_SCHD_TABLE_2_HW_BASED, 1); |
824 | REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, |
825 | AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); |
826 | |
827 | if (AR_SREV_9565(ah)) |
828 | REG_RMW_FIELD(ah, AR_MCI_MISC, AR_MCI_MISC_HW_FIX_EN, 1); |
829 | |
830 | if (!(mci->config & ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) { |
831 | thresh = MS(mci->config, ATH_MCI_CONFIG_AGGR_THRESH); |
832 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, |
833 | AR_BTCOEX_CTRL_AGGR_THRESH, thresh); |
834 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, |
835 | AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 1); |
836 | } else |
837 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, |
838 | AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN, 0); |
839 | |
840 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, |
841 | AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1); |
842 | } |
843 | |
844 | static void ar9003_mci_stat_setup(struct ath_hw *ah) |
845 | { |
846 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
847 | |
848 | if (!AR_SREV_9565(ah)) |
849 | return; |
850 | |
851 | if (mci->config & ATH_MCI_CONFIG_MCI_STAT_DBG) { |
852 | REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, |
853 | AR_MCI_DBG_CNT_CTRL_ENABLE, 1); |
854 | REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, |
855 | AR_MCI_DBG_CNT_CTRL_BT_LINKID, |
856 | MCI_STAT_ALL_BT_LINKID); |
857 | } else { |
858 | REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, |
859 | AR_MCI_DBG_CNT_CTRL_ENABLE, 0); |
860 | } |
861 | } |
862 | |
863 | static void ar9003_mci_set_btcoex_ctrl_9565_1ANT(struct ath_hw *ah) |
864 | { |
865 | u32 regval; |
866 | |
867 | regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | |
868 | SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | |
869 | SM(1, AR_BTCOEX_CTRL_PA_SHARED) | |
870 | SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | |
871 | SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | |
872 | SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | |
873 | SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | |
874 | SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | |
875 | SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); |
876 | |
877 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, |
878 | AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); |
879 | REG_WRITE(ah, AR_BTCOEX_CTRL, regval); |
880 | } |
881 | |
882 | static void ar9003_mci_set_btcoex_ctrl_9565_2ANT(struct ath_hw *ah) |
883 | { |
884 | u32 regval; |
885 | |
886 | regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | |
887 | SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | |
888 | SM(0, AR_BTCOEX_CTRL_PA_SHARED) | |
889 | SM(0, AR_BTCOEX_CTRL_LNA_SHARED) | |
890 | SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | |
891 | SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | |
892 | SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | |
893 | SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | |
894 | SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); |
895 | |
896 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, |
897 | AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x0); |
898 | REG_WRITE(ah, AR_BTCOEX_CTRL, regval); |
899 | } |
900 | |
901 | static void ar9003_mci_set_btcoex_ctrl_9462(struct ath_hw *ah) |
902 | { |
903 | u32 regval; |
904 | |
905 | regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | |
906 | SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | |
907 | SM(1, AR_BTCOEX_CTRL_PA_SHARED) | |
908 | SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | |
909 | SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | |
910 | SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | |
911 | SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | |
912 | SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | |
913 | SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); |
914 | |
915 | REG_WRITE(ah, AR_BTCOEX_CTRL, regval); |
916 | } |
917 | |
918 | int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, |
919 | bool is_full_sleep) |
920 | { |
921 | struct ath_common *common = ath9k_hw_common(ah); |
922 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
923 | u32 regval, i; |
924 | |
925 | ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n" , |
926 | is_full_sleep, is_2g); |
927 | |
928 | if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { |
929 | ath_err(common, "BTCOEX control register is dead\n" ); |
930 | return -EINVAL; |
931 | } |
932 | |
933 | /* Program MCI DMA related registers */ |
934 | REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr); |
935 | REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len); |
936 | REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr); |
937 | |
938 | /* |
939 | * To avoid MCI state machine be affected by incoming remote MCI msgs, |
940 | * MCI mode will be enabled later, right before reset the MCI TX and RX. |
941 | */ |
942 | if (AR_SREV_9565(ah)) { |
943 | u8 ant = MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH); |
944 | |
945 | if (ant == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED) |
946 | ar9003_mci_set_btcoex_ctrl_9565_1ANT(ah); |
947 | else |
948 | ar9003_mci_set_btcoex_ctrl_9565_2ANT(ah); |
949 | } else { |
950 | ar9003_mci_set_btcoex_ctrl_9462(ah); |
951 | } |
952 | |
953 | if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) |
954 | ar9003_mci_osla_setup(ah, enable: true); |
955 | else |
956 | ar9003_mci_osla_setup(ah, enable: false); |
957 | |
958 | REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, |
959 | AR_BTCOEX_CTRL_SPDT_ENABLE); |
960 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, |
961 | AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); |
962 | |
963 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 0); |
964 | REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); |
965 | |
966 | /* Set the time out to 3.125ms (5 BT slots) */ |
967 | REG_RMW_FIELD(ah, AR_BTCOEX_WL_LNA, AR_BTCOEX_WL_LNA_TIMEOUT, 0x3D090); |
968 | |
969 | /* concurrent tx priority */ |
970 | if (mci->config & ATH_MCI_CONFIG_CONCUR_TX) { |
971 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, |
972 | AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE, 0); |
973 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, |
974 | AR_BTCOEX_CTRL2_TXPWR_THRESH, 0x7f); |
975 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL, |
976 | AR_BTCOEX_CTRL_REDUCE_TXPWR, 0); |
977 | for (i = 0; i < 8; i++) |
978 | REG_WRITE(ah, AR_BTCOEX_MAX_TXPWR(i), 0x7f7f7f7f); |
979 | } |
980 | |
981 | regval = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); |
982 | REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, regval); |
983 | REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); |
984 | |
985 | /* Resetting the Rx and Tx paths of MCI */ |
986 | regval = REG_READ(ah, AR_MCI_COMMAND2); |
987 | regval |= SM(1, AR_MCI_COMMAND2_RESET_TX); |
988 | REG_WRITE(ah, AR_MCI_COMMAND2, regval); |
989 | |
990 | udelay(1); |
991 | |
992 | regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX); |
993 | REG_WRITE(ah, AR_MCI_COMMAND2, regval); |
994 | |
995 | if (is_full_sleep) { |
996 | ar9003_mci_mute_bt(ah); |
997 | udelay(100); |
998 | } |
999 | |
1000 | /* Check pending GPM msg before MCI Reset Rx */ |
1001 | ar9003_mci_check_gpm_offset(ah); |
1002 | |
1003 | regval |= SM(1, AR_MCI_COMMAND2_RESET_RX); |
1004 | REG_WRITE(ah, AR_MCI_COMMAND2, regval); |
1005 | udelay(1); |
1006 | regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); |
1007 | REG_WRITE(ah, AR_MCI_COMMAND2, regval); |
1008 | |
1009 | /* Init GPM offset after MCI Reset Rx */ |
1010 | ar9003_mci_state(ah, state_type: MCI_STATE_INIT_GPM_OFFSET); |
1011 | |
1012 | REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, |
1013 | (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | |
1014 | SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); |
1015 | |
1016 | if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) |
1017 | REG_CLR_BIT(ah, AR_MCI_TX_CTRL, |
1018 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); |
1019 | else |
1020 | REG_SET_BIT(ah, AR_MCI_TX_CTRL, |
1021 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); |
1022 | |
1023 | ar9003_mci_observation_set_up(ah); |
1024 | |
1025 | mci->ready = true; |
1026 | ar9003_mci_prep_interface(ah); |
1027 | ar9003_mci_stat_setup(ah); |
1028 | |
1029 | if (en_int) |
1030 | ar9003_mci_enable_interrupt(ah); |
1031 | |
1032 | if (ath9k_hw_is_aic_enabled(ah)) |
1033 | ar9003_aic_start_normal(ah); |
1034 | |
1035 | return 0; |
1036 | } |
1037 | |
1038 | void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep) |
1039 | { |
1040 | struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; |
1041 | |
1042 | ar9003_mci_disable_interrupt(ah); |
1043 | |
1044 | if (mci_hw->ready && !save_fullsleep) { |
1045 | ar9003_mci_mute_bt(ah); |
1046 | udelay(20); |
1047 | REG_WRITE(ah, AR_BTCOEX_CTRL, 0); |
1048 | } |
1049 | |
1050 | mci_hw->bt_state = MCI_BT_SLEEP; |
1051 | mci_hw->ready = false; |
1052 | } |
1053 | |
1054 | static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done) |
1055 | { |
1056 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1057 | u32 to_set, to_clear; |
1058 | |
1059 | if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP)) |
1060 | return; |
1061 | |
1062 | if (mci->is_2g) { |
1063 | to_clear = MCI_2G_FLAGS_CLEAR_MASK; |
1064 | to_set = MCI_2G_FLAGS_SET_MASK; |
1065 | } else { |
1066 | to_clear = MCI_5G_FLAGS_CLEAR_MASK; |
1067 | to_set = MCI_5G_FLAGS_SET_MASK; |
1068 | } |
1069 | |
1070 | if (to_clear) |
1071 | ar9003_mci_send_coex_bt_flags(ah, wait_done, |
1072 | opcode: MCI_GPM_COEX_BT_FLAGS_CLEAR, |
1073 | bt_flags: to_clear); |
1074 | if (to_set) |
1075 | ar9003_mci_send_coex_bt_flags(ah, wait_done, |
1076 | opcode: MCI_GPM_COEX_BT_FLAGS_SET, |
1077 | bt_flags: to_set); |
1078 | } |
1079 | |
1080 | static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 , |
1081 | u32 *payload, bool queue) |
1082 | { |
1083 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1084 | u8 type, opcode; |
1085 | |
1086 | /* check if the message is to be queued */ |
1087 | if (header != MCI_GPM) |
1088 | return; |
1089 | |
1090 | type = MCI_GPM_TYPE(payload); |
1091 | opcode = MCI_GPM_OPCODE(payload); |
1092 | |
1093 | if (type != MCI_GPM_COEX_AGENT) |
1094 | return; |
1095 | |
1096 | switch (opcode) { |
1097 | case MCI_GPM_COEX_BT_UPDATE_FLAGS: |
1098 | if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) == |
1099 | MCI_GPM_COEX_BT_FLAGS_READ) |
1100 | break; |
1101 | |
1102 | mci->update_2g5g = queue; |
1103 | |
1104 | break; |
1105 | case MCI_GPM_COEX_WLAN_CHANNELS: |
1106 | mci->wlan_channels_update = queue; |
1107 | break; |
1108 | case MCI_GPM_COEX_HALT_BT_GPM: |
1109 | if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == |
1110 | MCI_GPM_COEX_BT_GPM_UNHALT) { |
1111 | mci->unhalt_bt_gpm = queue; |
1112 | |
1113 | if (!queue) |
1114 | mci->halted_bt_gpm = false; |
1115 | } |
1116 | |
1117 | if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == |
1118 | MCI_GPM_COEX_BT_GPM_HALT) { |
1119 | |
1120 | mci->halted_bt_gpm = !queue; |
1121 | } |
1122 | |
1123 | break; |
1124 | default: |
1125 | break; |
1126 | } |
1127 | } |
1128 | |
1129 | void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) |
1130 | { |
1131 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1132 | |
1133 | if (!mci->update_2g5g && !force) |
1134 | return; |
1135 | |
1136 | if (mci->is_2g) { |
1137 | ar9003_mci_send_2g5g_status(ah, wait_done: true); |
1138 | ar9003_mci_send_lna_transfer(ah, wait_done: true); |
1139 | udelay(5); |
1140 | |
1141 | REG_CLR_BIT(ah, AR_MCI_TX_CTRL, |
1142 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); |
1143 | REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL, |
1144 | AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); |
1145 | |
1146 | if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) |
1147 | ar9003_mci_osla_setup(ah, enable: true); |
1148 | |
1149 | if (AR_SREV_9462(ah)) |
1150 | REG_WRITE(ah, AR_SELFGEN_MASK, 0x02); |
1151 | } else { |
1152 | ar9003_mci_send_lna_take(ah, wait_done: true); |
1153 | udelay(5); |
1154 | |
1155 | REG_SET_BIT(ah, AR_MCI_TX_CTRL, |
1156 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); |
1157 | REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, |
1158 | AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); |
1159 | |
1160 | ar9003_mci_osla_setup(ah, enable: false); |
1161 | ar9003_mci_send_2g5g_status(ah, wait_done: true); |
1162 | } |
1163 | } |
1164 | |
1165 | bool ar9003_mci_send_message(struct ath_hw *ah, u8 , u32 flag, |
1166 | u32 *payload, u8 len, bool wait_done, |
1167 | bool check_bt) |
1168 | { |
1169 | struct ath_common *common = ath9k_hw_common(ah); |
1170 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1171 | bool msg_sent = false; |
1172 | u32 regval; |
1173 | u32 saved_mci_int_en; |
1174 | int i; |
1175 | |
1176 | saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); |
1177 | regval = REG_READ(ah, AR_BTCOEX_CTRL); |
1178 | |
1179 | if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) { |
1180 | ath_dbg(common, MCI, |
1181 | "MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n" , |
1182 | header, (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0); |
1183 | ar9003_mci_queue_unsent_gpm(ah, header, payload, queue: true); |
1184 | return false; |
1185 | } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) { |
1186 | ath_dbg(common, MCI, |
1187 | "MCI Don't send message 0x%x. BT is in sleep state\n" , |
1188 | header); |
1189 | ar9003_mci_queue_unsent_gpm(ah, header, payload, queue: true); |
1190 | return false; |
1191 | } |
1192 | |
1193 | if (wait_done) |
1194 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); |
1195 | |
1196 | /* Need to clear SW_MSG_DONE raw bit before wait */ |
1197 | |
1198 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, |
1199 | (AR_MCI_INTERRUPT_SW_MSG_DONE | |
1200 | AR_MCI_INTERRUPT_MSG_FAIL_MASK)); |
1201 | |
1202 | if (payload) { |
1203 | for (i = 0; (i * 4) < len; i++) |
1204 | REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4), |
1205 | *(payload + i)); |
1206 | } |
1207 | |
1208 | REG_WRITE(ah, AR_MCI_COMMAND0, |
1209 | (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP), |
1210 | AR_MCI_COMMAND0_DISABLE_TIMESTAMP) | |
1211 | SM(len, AR_MCI_COMMAND0_LEN) | |
1212 | SM(header, AR_MCI_COMMAND0_HEADER))); |
1213 | |
1214 | if (wait_done && |
1215 | !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW, |
1216 | AR_MCI_INTERRUPT_SW_MSG_DONE, time_out: 500))) |
1217 | ar9003_mci_queue_unsent_gpm(ah, header, payload, queue: true); |
1218 | else { |
1219 | ar9003_mci_queue_unsent_gpm(ah, header, payload, queue: false); |
1220 | msg_sent = true; |
1221 | } |
1222 | |
1223 | if (wait_done) |
1224 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); |
1225 | |
1226 | return msg_sent; |
1227 | } |
1228 | EXPORT_SYMBOL(ar9003_mci_send_message); |
1229 | |
1230 | void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable) |
1231 | { |
1232 | struct ath_common *common = ath9k_hw_common(ah); |
1233 | struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; |
1234 | u32 pld[4] = {0, 0, 0, 0}; |
1235 | |
1236 | if ((mci_hw->bt_state != MCI_BT_AWAKE) || |
1237 | (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) |
1238 | return; |
1239 | |
1240 | MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ); |
1241 | pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++; |
1242 | |
1243 | ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); |
1244 | |
1245 | if (ar9003_mci_wait_for_gpm(ah, gpm_type: MCI_GPM_BT_CAL_GRANT, gpm_opcode: 0, time_out: 50000)) { |
1246 | ath_dbg(common, MCI, "MCI BT_CAL_GRANT received\n" ); |
1247 | } else { |
1248 | *is_reusable = false; |
1249 | ath_dbg(common, MCI, "MCI BT_CAL_GRANT not received\n" ); |
1250 | } |
1251 | } |
1252 | |
1253 | void ar9003_mci_init_cal_done(struct ath_hw *ah) |
1254 | { |
1255 | struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; |
1256 | u32 pld[4] = {0, 0, 0, 0}; |
1257 | |
1258 | if ((mci_hw->bt_state != MCI_BT_AWAKE) || |
1259 | (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) |
1260 | return; |
1261 | |
1262 | MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE); |
1263 | pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++; |
1264 | ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false); |
1265 | } |
1266 | |
1267 | int ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, |
1268 | u16 len, u32 sched_addr) |
1269 | { |
1270 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1271 | |
1272 | mci->gpm_addr = gpm_addr; |
1273 | mci->gpm_buf = gpm_buf; |
1274 | mci->gpm_len = len; |
1275 | mci->sched_addr = sched_addr; |
1276 | |
1277 | return ar9003_mci_reset(ah, en_int: true, is_2g: true, is_full_sleep: true); |
1278 | } |
1279 | EXPORT_SYMBOL(ar9003_mci_setup); |
1280 | |
1281 | void ar9003_mci_cleanup(struct ath_hw *ah) |
1282 | { |
1283 | /* Turn off MCI and Jupiter mode. */ |
1284 | REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00); |
1285 | ar9003_mci_disable_interrupt(ah); |
1286 | } |
1287 | EXPORT_SYMBOL(ar9003_mci_cleanup); |
1288 | |
1289 | u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) |
1290 | { |
1291 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1292 | u32 value = 0, tsf; |
1293 | u8 query_type; |
1294 | |
1295 | switch (state_type) { |
1296 | case MCI_STATE_ENABLE: |
1297 | if (mci->ready) { |
1298 | value = REG_READ(ah, AR_BTCOEX_CTRL); |
1299 | |
1300 | if ((value == 0xdeadbeef) || (value == 0xffffffff)) |
1301 | value = 0; |
1302 | } |
1303 | value &= AR_BTCOEX_CTRL_MCI_MODE_EN; |
1304 | break; |
1305 | case MCI_STATE_INIT_GPM_OFFSET: |
1306 | value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); |
1307 | |
1308 | if (value < mci->gpm_len) |
1309 | mci->gpm_idx = value; |
1310 | else |
1311 | mci->gpm_idx = 0; |
1312 | break; |
1313 | case MCI_STATE_LAST_SCHD_MSG_OFFSET: |
1314 | value = MS(REG_READ(ah, AR_MCI_RX_STATUS), |
1315 | AR_MCI_RX_LAST_SCHD_MSG_INDEX); |
1316 | /* Make it in bytes */ |
1317 | value <<= 4; |
1318 | break; |
1319 | case MCI_STATE_REMOTE_SLEEP: |
1320 | value = MS(REG_READ(ah, AR_MCI_RX_STATUS), |
1321 | AR_MCI_RX_REMOTE_SLEEP) ? |
1322 | MCI_BT_SLEEP : MCI_BT_AWAKE; |
1323 | break; |
1324 | case MCI_STATE_SET_BT_AWAKE: |
1325 | mci->bt_state = MCI_BT_AWAKE; |
1326 | ar9003_mci_send_coex_version_query(ah, wait_done: true); |
1327 | ar9003_mci_send_coex_wlan_channels(ah, wait_done: true); |
1328 | |
1329 | if (mci->unhalt_bt_gpm) |
1330 | ar9003_mci_send_coex_halt_bt_gpm(ah, halt: false, wait_done: true); |
1331 | |
1332 | ar9003_mci_2g5g_switch(ah, force: false); |
1333 | break; |
1334 | case MCI_STATE_RESET_REQ_WAKE: |
1335 | ar9003_mci_reset_req_wakeup(ah); |
1336 | mci->update_2g5g = true; |
1337 | |
1338 | if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK) { |
1339 | /* Check if we still have control of the GPIOs */ |
1340 | if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & |
1341 | ATH_MCI_CONFIG_MCI_OBS_GPIO) != |
1342 | ATH_MCI_CONFIG_MCI_OBS_GPIO) { |
1343 | ar9003_mci_observation_set_up(ah); |
1344 | } |
1345 | } |
1346 | break; |
1347 | case MCI_STATE_SEND_WLAN_COEX_VERSION: |
1348 | ar9003_mci_send_coex_version_response(ah, wait_done: true); |
1349 | break; |
1350 | case MCI_STATE_SEND_VERSION_QUERY: |
1351 | ar9003_mci_send_coex_version_query(ah, wait_done: true); |
1352 | break; |
1353 | case MCI_STATE_SEND_STATUS_QUERY: |
1354 | query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY; |
1355 | ar9003_mci_send_coex_bt_status_query(ah, wait_done: true, query_type); |
1356 | break; |
1357 | case MCI_STATE_RECOVER_RX: |
1358 | tsf = ath9k_hw_gettsf32(ah); |
1359 | if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) { |
1360 | ath_dbg(ath9k_hw_common(ah), MCI, |
1361 | "(MCI) ignore Rx recovery\n" ); |
1362 | break; |
1363 | } |
1364 | ath_dbg(ath9k_hw_common(ah), MCI, "(MCI) RECOVER RX\n" ); |
1365 | mci->last_recovery = tsf; |
1366 | ar9003_mci_prep_interface(ah); |
1367 | mci->query_bt = true; |
1368 | mci->need_flush_btinfo = true; |
1369 | ar9003_mci_send_coex_wlan_channels(ah, wait_done: true); |
1370 | ar9003_mci_2g5g_switch(ah, force: false); |
1371 | break; |
1372 | case MCI_STATE_NEED_FTP_STOMP: |
1373 | value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); |
1374 | break; |
1375 | case MCI_STATE_NEED_FLUSH_BT_INFO: |
1376 | value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; |
1377 | mci->need_flush_btinfo = false; |
1378 | break; |
1379 | case MCI_STATE_AIC_CAL: |
1380 | if (ath9k_hw_is_aic_enabled(ah)) |
1381 | value = ar9003_aic_calibration(ah); |
1382 | break; |
1383 | case MCI_STATE_AIC_START: |
1384 | if (ath9k_hw_is_aic_enabled(ah)) |
1385 | ar9003_aic_start_normal(ah); |
1386 | break; |
1387 | case MCI_STATE_AIC_CAL_RESET: |
1388 | if (ath9k_hw_is_aic_enabled(ah)) |
1389 | value = ar9003_aic_cal_reset(ah); |
1390 | break; |
1391 | case MCI_STATE_AIC_CAL_SINGLE: |
1392 | if (ath9k_hw_is_aic_enabled(ah)) |
1393 | value = ar9003_aic_calibration_single(ah); |
1394 | break; |
1395 | default: |
1396 | break; |
1397 | } |
1398 | |
1399 | return value; |
1400 | } |
1401 | EXPORT_SYMBOL(ar9003_mci_state); |
1402 | |
1403 | void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah) |
1404 | { |
1405 | struct ath_common *common = ath9k_hw_common(ah); |
1406 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1407 | |
1408 | ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n" ); |
1409 | |
1410 | ar9003_mci_send_lna_take(ah, wait_done: true); |
1411 | udelay(50); |
1412 | |
1413 | REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); |
1414 | mci->is_2g = false; |
1415 | mci->update_2g5g = true; |
1416 | ar9003_mci_send_2g5g_status(ah, wait_done: true); |
1417 | |
1418 | /* Force another 2g5g update at next scanning */ |
1419 | mci->update_2g5g = true; |
1420 | } |
1421 | |
1422 | void ar9003_mci_set_power_awake(struct ath_hw *ah) |
1423 | { |
1424 | u32 btcoex_ctrl2, diag_sw; |
1425 | int i; |
1426 | u8 lna_ctrl, bt_sleep; |
1427 | |
1428 | for (i = 0; i < AH_WAIT_TIMEOUT; i++) { |
1429 | btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2); |
1430 | if (btcoex_ctrl2 != 0xdeadbeef) |
1431 | break; |
1432 | udelay(AH_TIME_QUANTUM); |
1433 | } |
1434 | REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23))); |
1435 | |
1436 | for (i = 0; i < AH_WAIT_TIMEOUT; i++) { |
1437 | diag_sw = REG_READ(ah, AR_DIAG_SW); |
1438 | if (diag_sw != 0xdeadbeef) |
1439 | break; |
1440 | udelay(AH_TIME_QUANTUM); |
1441 | } |
1442 | REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18))); |
1443 | lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3; |
1444 | bt_sleep = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_REMOTE_SLEEP); |
1445 | |
1446 | REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2); |
1447 | REG_WRITE(ah, AR_DIAG_SW, diag_sw); |
1448 | |
1449 | if (bt_sleep && (lna_ctrl == 2)) { |
1450 | REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1); |
1451 | REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1); |
1452 | udelay(50); |
1453 | } |
1454 | } |
1455 | |
1456 | void ar9003_mci_check_gpm_offset(struct ath_hw *ah) |
1457 | { |
1458 | struct ath_common *common = ath9k_hw_common(ah); |
1459 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1460 | u32 offset; |
1461 | |
1462 | /* |
1463 | * This should only be called before "MAC Warm Reset" or "MCI Reset Rx". |
1464 | */ |
1465 | offset = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); |
1466 | if (mci->gpm_idx == offset) |
1467 | return; |
1468 | ath_dbg(common, MCI, "GPM cached write pointer mismatch %d %d\n" , |
1469 | mci->gpm_idx, offset); |
1470 | mci->query_bt = true; |
1471 | mci->need_flush_btinfo = true; |
1472 | mci->gpm_idx = 0; |
1473 | } |
1474 | |
1475 | u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, u32 *more) |
1476 | { |
1477 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1478 | u32 offset, more_gpm = 0, gpm_ptr; |
1479 | |
1480 | /* |
1481 | * This could be useful to avoid new GPM message interrupt which |
1482 | * may lead to spurious interrupt after power sleep, or multiple |
1483 | * entry of ath_mci_intr(). |
1484 | * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can |
1485 | * alleviate this effect, but clearing GPM RX interrupt bit is |
1486 | * safe, because whether this is called from hw or driver code |
1487 | * there must be an interrupt bit set/triggered initially |
1488 | */ |
1489 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, |
1490 | AR_MCI_INTERRUPT_RX_MSG_GPM); |
1491 | |
1492 | gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); |
1493 | offset = gpm_ptr; |
1494 | |
1495 | if (!offset) |
1496 | offset = mci->gpm_len - 1; |
1497 | else if (offset >= mci->gpm_len) { |
1498 | if (offset != 0xFFFF) |
1499 | offset = 0; |
1500 | } else { |
1501 | offset--; |
1502 | } |
1503 | |
1504 | if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) { |
1505 | offset = MCI_GPM_INVALID; |
1506 | more_gpm = MCI_GPM_NOMORE; |
1507 | goto out; |
1508 | } |
1509 | for (;;) { |
1510 | u32 temp_index; |
1511 | |
1512 | /* skip reserved GPM if any */ |
1513 | |
1514 | if (offset != mci->gpm_idx) |
1515 | more_gpm = MCI_GPM_MORE; |
1516 | else |
1517 | more_gpm = MCI_GPM_NOMORE; |
1518 | |
1519 | temp_index = mci->gpm_idx; |
1520 | |
1521 | if (temp_index >= mci->gpm_len) |
1522 | temp_index = 0; |
1523 | |
1524 | mci->gpm_idx++; |
1525 | |
1526 | if (mci->gpm_idx >= mci->gpm_len) |
1527 | mci->gpm_idx = 0; |
1528 | |
1529 | if (ar9003_mci_is_gpm_valid(ah, msg_index: temp_index)) { |
1530 | offset = temp_index; |
1531 | break; |
1532 | } |
1533 | |
1534 | if (more_gpm == MCI_GPM_NOMORE) { |
1535 | offset = MCI_GPM_INVALID; |
1536 | break; |
1537 | } |
1538 | } |
1539 | |
1540 | if (offset != MCI_GPM_INVALID) |
1541 | offset <<= 4; |
1542 | out: |
1543 | if (more) |
1544 | *more = more_gpm; |
1545 | |
1546 | return offset; |
1547 | } |
1548 | EXPORT_SYMBOL(ar9003_mci_get_next_gpm_offset); |
1549 | |
1550 | void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor) |
1551 | { |
1552 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1553 | |
1554 | mci->bt_ver_major = major; |
1555 | mci->bt_ver_minor = minor; |
1556 | mci->bt_version_known = true; |
1557 | ath_dbg(ath9k_hw_common(ah), MCI, "MCI BT version set: %d.%d\n" , |
1558 | mci->bt_ver_major, mci->bt_ver_minor); |
1559 | } |
1560 | EXPORT_SYMBOL(ar9003_mci_set_bt_version); |
1561 | |
1562 | void ar9003_mci_send_wlan_channels(struct ath_hw *ah) |
1563 | { |
1564 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; |
1565 | |
1566 | mci->wlan_channels_update = true; |
1567 | ar9003_mci_send_coex_wlan_channels(ah, wait_done: true); |
1568 | } |
1569 | EXPORT_SYMBOL(ar9003_mci_send_wlan_channels); |
1570 | |
1571 | u16 ar9003_mci_get_max_txpower(struct ath_hw *ah, u8 ctlmode) |
1572 | { |
1573 | if (!ah->btcoex_hw.mci.concur_tx) |
1574 | goto out; |
1575 | |
1576 | if (ctlmode == CTL_2GHT20) |
1577 | return ATH_BTCOEX_HT20_MAX_TXPOWER; |
1578 | else if (ctlmode == CTL_2GHT40) |
1579 | return ATH_BTCOEX_HT40_MAX_TXPOWER; |
1580 | |
1581 | out: |
1582 | return -1; |
1583 | } |
1584 | |