blob: 597e707a0c73dabd9da9e65f7d71c2de7c298d07 [file] [log] [blame]
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301/*
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"
Sujith Manoharan528e5d32012-02-22 12:41:12 +053019#include "hw-ops.h"
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +053020#include "ar9003_phy.h"
21#include "ar9003_mci.h"
22
23static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah)
24{
25 if (!AR_SREV_9462_20(ah))
26 return;
27
28 REG_RMW_FIELD(ah, AR_MCI_COMMAND2,
29 AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1);
30 udelay(1);
31 REG_RMW_FIELD(ah, AR_MCI_COMMAND2,
32 AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 0);
33}
34
35static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
36 u32 bit_position, int time_out)
37{
38 struct ath_common *common = ath9k_hw_common(ah);
39
40 while (time_out) {
41
42 if (REG_READ(ah, address) & bit_position) {
43
44 REG_WRITE(ah, address, bit_position);
45
46 if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
47
48 if (bit_position &
49 AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
50 ar9003_mci_reset_req_wakeup(ah);
51
52 if (bit_position &
53 (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
54 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
55 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
56 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
57
58 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
59 AR_MCI_INTERRUPT_RX_MSG);
60 }
61 break;
62 }
63
64 udelay(10);
65 time_out -= 10;
66
67 if (time_out < 0)
68 break;
69 }
70
71 if (time_out <= 0) {
Joe Perchesd2182b62011-12-15 14:55:53 -080072 ath_dbg(common, MCI,
73 "MCI Wait for Reg 0x%08x = 0x%08x timeout\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +053074 address, bit_position);
Joe Perchesd2182b62011-12-15 14:55:53 -080075 ath_dbg(common, MCI,
76 "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +053077 REG_READ(ah, AR_MCI_INTERRUPT_RAW),
78 REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW));
79 time_out = 0;
80 }
81
82 return time_out;
83}
84
85void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done)
86{
87 u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00};
88
Felix Fietkau8a309302011-12-17 16:47:56 +010089 if (!ATH9K_HW_CAP_MCI)
90 return;
91
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +053092 ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16,
93 wait_done, false);
94 udelay(5);
95}
96
97void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done)
98{
99 u32 payload = 0x00000000;
100
Felix Fietkau8a309302011-12-17 16:47:56 +0100101 if (!ATH9K_HW_CAP_MCI)
102 return;
103
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530104 ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1,
105 wait_done, false);
106}
107
108static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done)
109{
110 ar9003_mci_send_message(ah, MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP,
111 NULL, 0, wait_done, false);
112 udelay(5);
113}
114
115void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done)
116{
Felix Fietkau8a309302011-12-17 16:47:56 +0100117 if (!ATH9K_HW_CAP_MCI)
118 return;
119
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530120 ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP,
121 NULL, 0, wait_done, false);
122}
123
124static void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done)
125{
126 u32 payload = 0x70000000;
127
128 ar9003_mci_send_message(ah, MCI_LNA_TAKE, 0, &payload, 1,
129 wait_done, false);
130}
131
132static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done)
133{
134 ar9003_mci_send_message(ah, MCI_SYS_SLEEPING,
135 MCI_FLAG_DISABLE_TIMESTAMP,
136 NULL, 0, wait_done, false);
137}
138
139static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
140 bool wait_done)
141{
142 struct ath_common *common = ath9k_hw_common(ah);
143 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
144 u32 payload[4] = {0, 0, 0, 0};
145
146 if (!mci->bt_version_known &&
147 (mci->bt_state != MCI_BT_SLEEP)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800148 ath_dbg(common, MCI, "MCI Send Coex version query\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530149 MCI_GPM_SET_TYPE_OPCODE(payload,
150 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_VERSION_QUERY);
151 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
152 wait_done, true);
153 }
154}
155
156static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
157 bool wait_done)
158{
159 struct ath_common *common = ath9k_hw_common(ah);
160 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
161 u32 payload[4] = {0, 0, 0, 0};
162
Joe Perchesd2182b62011-12-15 14:55:53 -0800163 ath_dbg(common, MCI, "MCI Send Coex version response\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530164 MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
165 MCI_GPM_COEX_VERSION_RESPONSE);
166 *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) =
167 mci->wlan_ver_major;
168 *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) =
169 mci->wlan_ver_minor;
170 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
171}
172
173static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
174 bool wait_done)
175{
176 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
177 u32 *payload = &mci->wlan_channels[0];
178
179 if ((mci->wlan_channels_update == true) &&
180 (mci->bt_state != MCI_BT_SLEEP)) {
181 MCI_GPM_SET_TYPE_OPCODE(payload,
182 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_WLAN_CHANNELS);
183 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
184 wait_done, true);
185 MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
186 }
187}
188
189static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
190 bool wait_done, u8 query_type)
191{
192 struct ath_common *common = ath9k_hw_common(ah);
193 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
194 u32 payload[4] = {0, 0, 0, 0};
195 bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
196 MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
197
198 if (mci->bt_state != MCI_BT_SLEEP) {
199
Joe Perchesd2182b62011-12-15 14:55:53 -0800200 ath_dbg(common, MCI, "MCI Send Coex BT Status Query 0x%02X\n",
201 query_type);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530202
203 MCI_GPM_SET_TYPE_OPCODE(payload,
204 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_STATUS_QUERY);
205
206 *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
207 /*
208 * If bt_status_query message is not sent successfully,
209 * then need_flush_btinfo should be set again.
210 */
211 if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
212 wait_done, true)) {
213 if (query_btinfo) {
214 mci->need_flush_btinfo = true;
215
Joe Perchesd2182b62011-12-15 14:55:53 -0800216 ath_dbg(common, MCI,
217 "MCI send bt_status_query fail, set flush flag again\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530218 }
219 }
220
221 if (query_btinfo)
222 mci->query_bt = false;
223 }
224}
225
226void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
227 bool wait_done)
228{
229 struct ath_common *common = ath9k_hw_common(ah);
230 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
231 u32 payload[4] = {0, 0, 0, 0};
232
Felix Fietkau8a309302011-12-17 16:47:56 +0100233 if (!ATH9K_HW_CAP_MCI)
234 return;
235
Joe Perchesd2182b62011-12-15 14:55:53 -0800236 ath_dbg(common, MCI, "MCI Send Coex %s BT GPM\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530237 (halt) ? "halt" : "unhalt");
238
239 MCI_GPM_SET_TYPE_OPCODE(payload,
240 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_HALT_BT_GPM);
241
242 if (halt) {
243 mci->query_bt = true;
244 /* Send next unhalt no matter halt sent or not */
245 mci->unhalt_bt_gpm = true;
246 mci->need_flush_btinfo = true;
247 *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) =
248 MCI_GPM_COEX_BT_GPM_HALT;
249 } else
250 *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) =
251 MCI_GPM_COEX_BT_GPM_UNHALT;
252
253 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
254}
255
256
257static void ar9003_mci_prep_interface(struct ath_hw *ah)
258{
259 struct ath_common *common = ath9k_hw_common(ah);
260 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
261 u32 saved_mci_int_en;
262 u32 mci_timeout = 150;
263
264 mci->bt_state = MCI_BT_SLEEP;
265 saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
266
267 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
268 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
269 REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW));
270 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
271 REG_READ(ah, AR_MCI_INTERRUPT_RAW));
272
273 /* Remote Reset */
Joe Perchesd2182b62011-12-15 14:55:53 -0800274 ath_dbg(common, MCI, "MCI Reset sequence start\n");
275 ath_dbg(common, MCI, "MCI send REMOTE_RESET\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530276 ar9003_mci_remote_reset(ah, true);
277
Joe Perchesd2182b62011-12-15 14:55:53 -0800278 ath_dbg(common, MCI, "MCI Send REQ_WAKE to remoter(BT)\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530279 ar9003_mci_send_req_wake(ah, true);
280
281 if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
282 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
283
Joe Perchesd2182b62011-12-15 14:55:53 -0800284 ath_dbg(common, MCI, "MCI SYS_WAKING from remote(BT)\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530285 mci->bt_state = MCI_BT_AWAKE;
286
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530287 /*
288 * we don't need to send more remote_reset at this moment.
289 * If BT receive first remote_reset, then BT HW will
290 * be cleaned up and will be able to receive req_wake
291 * and BT HW will respond sys_waking.
292 * In this case, WLAN will receive BT's HW sys_waking.
293 * Otherwise, if BT SW missed initial remote_reset,
294 * that remote_reset will still clean up BT MCI RX,
295 * and the req_wake will wake BT up,
296 * and BT SW will respond this req_wake with a remote_reset and
297 * sys_waking. In this case, WLAN will receive BT's SW
298 * sys_waking. In either case, BT's RX is cleaned up. So we
299 * don't need to reply BT's remote_reset now, if any.
300 * Similarly, if in any case, WLAN can receive BT's sys_waking,
301 * that means WLAN's RX is also fine.
302 */
303
304 /* Send SYS_WAKING to BT */
305
Joe Perchesd2182b62011-12-15 14:55:53 -0800306 ath_dbg(common, MCI, "MCI send SW SYS_WAKING to remote BT\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530307
308 ar9003_mci_send_sys_waking(ah, true);
309 udelay(10);
310
311 /*
312 * Set BT priority interrupt value to be 0xff to
313 * avoid having too many BT PRIORITY interrupts.
314 */
315
316 REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
317 REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
318 REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
319 REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
320 REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
321
322 /*
323 * A contention reset will be received after send out
324 * sys_waking. Also BT priority interrupt bits will be set.
325 * Clear those bits before the next step.
326 */
327
328 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
329 AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
330 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
331 AR_MCI_INTERRUPT_BT_PRI);
332
Sujith Manoharanc91ec462012-02-22 12:40:03 +0530333 if (mci->is_2g) {
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530334 /* Send LNA_TRANS */
Joe Perchesd2182b62011-12-15 14:55:53 -0800335 ath_dbg(common, MCI, "MCI send LNA_TRANS to BT\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530336 ar9003_mci_send_lna_transfer(ah, true);
337 udelay(5);
338 }
339
Sujith Manoharanc91ec462012-02-22 12:40:03 +0530340 if ((mci->is_2g && !mci->update_2g5g)) {
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530341 if (ar9003_mci_wait_for_interrupt(ah,
342 AR_MCI_INTERRUPT_RX_MSG_RAW,
343 AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
344 mci_timeout))
Joe Perchesd2182b62011-12-15 14:55:53 -0800345 ath_dbg(common, MCI,
346 "MCI WLAN has control over the LNA & BT obeys it\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530347 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800348 ath_dbg(common, MCI,
349 "MCI BT didn't respond to LNA_TRANS\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530350 }
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530351 }
352
353 /* Clear the extra redundant SYS_WAKING from BT */
354 if ((mci->bt_state == MCI_BT_AWAKE) &&
355 (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
356 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
357 (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
358 AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
359
360 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
361 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING);
362 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
363 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
364 }
365
366 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
367}
368
Sujith Manoharand1ca8b82012-02-22 12:41:01 +0530369void ar9003_mci_set_full_sleep(struct ath_hw *ah)
370{
371 struct ath_common *common = ath9k_hw_common(ah);
372 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
373
374 if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
375 (mci->bt_state != MCI_BT_SLEEP) &&
376 !mci->halted_bt_gpm) {
377 ath_dbg(common, MCI,
378 "MCI halt BT GPM (full_sleep)\n");
379 ar9003_mci_send_coex_halt_bt_gpm(ah, true, true);
380 }
381
382 mci->ready = false;
383 REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
384}
385
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530386void ar9003_mci_disable_interrupt(struct ath_hw *ah)
387{
Felix Fietkau8a309302011-12-17 16:47:56 +0100388 if (!ATH9K_HW_CAP_MCI)
389 return;
390
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530391 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
392 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
393}
394
395void ar9003_mci_enable_interrupt(struct ath_hw *ah)
396{
Felix Fietkau8a309302011-12-17 16:47:56 +0100397 if (!ATH9K_HW_CAP_MCI)
398 return;
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530399
400 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT);
401 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
402 AR_MCI_INTERRUPT_RX_MSG_DEFAULT);
403}
404
405bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints)
406{
407 u32 intr;
408
Felix Fietkau8a309302011-12-17 16:47:56 +0100409 if (!ATH9K_HW_CAP_MCI)
410 return false;
411
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530412 intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
413 return ((intr & ints) == ints);
414}
415
416void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
417 u32 *rx_msg_intr)
418{
419 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
Felix Fietkau8a309302011-12-17 16:47:56 +0100420
421 if (!ATH9K_HW_CAP_MCI)
422 return;
423
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530424 *raw_intr = mci->raw_intr;
425 *rx_msg_intr = mci->rx_msg_intr;
426
427 /* Clean int bits after the values are read. */
428 mci->raw_intr = 0;
429 mci->rx_msg_intr = 0;
430}
431EXPORT_SYMBOL(ar9003_mci_get_interrupt);
432
Sujith Manoharan5a1e2732012-02-22 12:40:55 +0530433void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
434{
435 struct ath_common *common = ath9k_hw_common(ah);
436 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
437 u32 raw_intr, rx_msg_intr;
438
439 rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
440 raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
441
442 if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) {
443 ath_dbg(common, MCI,
444 "MCI gets 0xdeadbeef during int processing\n");
445 } else {
446 mci->rx_msg_intr |= rx_msg_intr;
447 mci->raw_intr |= raw_intr;
448 *masked |= ATH9K_INT_MCI;
449
450 if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
451 mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS);
452
453 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
454 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
455 }
456}
457
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530458void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)
459{
460 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
461
Felix Fietkau8a309302011-12-17 16:47:56 +0100462 if (!ATH9K_HW_CAP_MCI)
463 return;
464
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530465 if (!mci->update_2g5g &&
466 (mci->is_2g != is_2g))
467 mci->update_2g5g = true;
468
469 mci->is_2g = is_2g;
470}
471
472static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index)
473{
474 struct ath_common *common = ath9k_hw_common(ah);
475 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
476 u32 *payload;
477 u32 recv_type, offset;
478
479 if (msg_index == MCI_GPM_INVALID)
480 return false;
481
482 offset = msg_index << 4;
483
484 payload = (u32 *)(mci->gpm_buf + offset);
485 recv_type = MCI_GPM_TYPE(payload);
486
487 if (recv_type == MCI_GPM_RSVD_PATTERN) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800488 ath_dbg(common, MCI, "MCI Skip RSVD GPM\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530489 return false;
490 }
491
492 return true;
493}
494
495static void ar9003_mci_observation_set_up(struct ath_hw *ah)
496{
497 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
498 if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {
499
500 ath9k_hw_cfg_output(ah, 3,
501 AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
502 ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK);
503 ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
504 ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
505
506 } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) {
507
508 ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX);
509 ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX);
510 ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
511 ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
512 ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
513
514 } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) {
515
516 ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
517 ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
518 ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
519 ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
520
521 } else
522 return;
523
524 REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
525
526 if (AR_SREV_9462_20_OR_LATER(ah)) {
527 REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
528 AR_GLB_DS_JTAG_DISABLE, 1);
529 REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
530 AR_GLB_WLAN_UART_INTF_EN, 0);
531 REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL,
532 ATH_MCI_CONFIG_MCI_OBS_GPIO);
533 }
534
535 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0);
536 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1);
537 REG_WRITE(ah, AR_OBS, 0x4b);
538 REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03);
539 REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01);
540 REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02);
541 REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03);
542 REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS,
543 AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07);
544}
545
546static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done,
547 u8 opcode, u32 bt_flags)
548{
549 struct ath_common *common = ath9k_hw_common(ah);
550 u32 pld[4] = {0, 0, 0, 0};
551
552 MCI_GPM_SET_TYPE_OPCODE(pld,
553 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_BT_UPDATE_FLAGS);
554
555 *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode;
556 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF;
557 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF;
558 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF;
559 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF;
560
Joe Perchesd2182b62011-12-15 14:55:53 -0800561 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530562 "MCI BT_MCI_FLAGS: Send Coex BT Update Flags %s 0x%08x\n",
Joe Perchesd2182b62011-12-15 14:55:53 -0800563 opcode == MCI_GPM_COEX_BT_FLAGS_READ ? "READ" :
564 opcode == MCI_GPM_COEX_BT_FLAGS_SET ? "SET" : "CLEAR",
565 bt_flags);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530566
567 return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16,
568 wait_done, true);
569}
570
Sujith Manoharan528e5d32012-02-22 12:41:12 +0530571void ar9003_mci_check_bt(struct ath_hw *ah)
572{
573 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
574
575 if (!mci_hw->ready)
576 return;
577
578 /*
579 * check BT state again to make
580 * sure it's not changed.
581 */
582 ar9003_mci_sync_bt_state(ah);
583 ar9003_mci_2g5g_switch(ah, true);
584
585 if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
586 (mci_hw->query_bt == true)) {
587 mci_hw->need_flush_btinfo = true;
588 }
589}
590
591bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan)
592{
593 struct ath_common *common = ath9k_hw_common(ah);
594 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
595 u32 payload[4] = {0, 0, 0, 0};
596
597 ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
598
599 if (mci_hw->bt_state != MCI_BT_CAL_START)
600 return false;
601
602 ath_dbg(common, MCI, "MCI stop rx for BT CAL\n");
603
604 mci_hw->bt_state = MCI_BT_CAL;
605
606 /*
607 * MCI FIX: disable mci interrupt here. This is to avoid
608 * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
609 * lead to mci_intr reentry.
610 */
611
612 ar9003_mci_disable_interrupt(ah);
613
614 ath_dbg(common, MCI, "send WLAN_CAL_GRANT\n");
615
616 MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
617 ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
618 16, true, false);
619
620 ath_dbg(common, MCI, "\nMCI BT is calibrating\n");
621
622 /* Wait BT calibration to be completed for 25ms */
623
624 if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
625 0, 25000))
626 ath_dbg(common, MCI,
627 "MCI got BT_CAL_DONE\n");
628 else
629 ath_dbg(common, MCI,
630 "MCI ### BT cal takes to long, force bt_state to be bt_awake\n");
631
632 mci_hw->bt_state = MCI_BT_AWAKE;
633 /* MCI FIX: enable mci interrupt here */
634 ar9003_mci_enable_interrupt(ah);
635
636 return true;
637}
638
639int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
640 struct ath9k_hw_cal_data *caldata)
641{
642 struct ath_common *common = ath9k_hw_common(ah);
643 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
644
645 if (!mci_hw->ready)
646 return 0;
647
648 if (!IS_CHAN_2GHZ(chan) || (mci_hw->bt_state != MCI_BT_SLEEP))
649 goto exit;
650
651 if (ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
652 ar9003_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
653
654 /*
655 * BT is sleeping. Check if BT wakes up during
656 * WLAN calibration. If BT wakes up during
657 * WLAN calibration, need to go through all
658 * message exchanges again and recal.
659 */
660
661 ath_dbg(common, MCI,
662 "MCI BT wakes up during WLAN calibration\n");
663
664 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
665 AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
666 AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
667
668 ath_dbg(common, MCI, "MCI send REMOTE_RESET\n");
669
670 ar9003_mci_remote_reset(ah, true);
671 ar9003_mci_send_sys_waking(ah, true);
672 udelay(1);
673
674 if (IS_CHAN_2GHZ(chan))
675 ar9003_mci_send_lna_transfer(ah, true);
676
677 mci_hw->bt_state = MCI_BT_AWAKE;
678
679 ath_dbg(common, MCI, "MCI re-cal\n");
680
681 if (caldata) {
682 caldata->done_txiqcal_once = false;
683 caldata->done_txclcal_once = false;
684 caldata->rtt_hist.num_readings = 0;
685 }
686
687 if (!ath9k_hw_init_cal(ah, chan))
688 return -EIO;
689
690 }
691exit:
692 ar9003_mci_enable_interrupt(ah);
693 return 0;
694}
695
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530696void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
697 bool is_full_sleep)
698{
699 struct ath_common *common = ath9k_hw_common(ah);
700 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
701 u32 regval, thresh;
702
Felix Fietkau8a309302011-12-17 16:47:56 +0100703 if (!ATH9K_HW_CAP_MCI)
704 return;
705
Joe Perchesd2182b62011-12-15 14:55:53 -0800706 ath_dbg(common, MCI, "MCI full_sleep = %d, is_2g = %d\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530707 is_full_sleep, is_2g);
708
709 /*
710 * GPM buffer and scheduling message buffer are not allocated
711 */
712
713 if (!mci->gpm_addr && !mci->sched_addr) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800714 ath_dbg(common, MCI,
715 "MCI GPM and schedule buffers are not allocated\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530716 return;
717 }
718
719 if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800720 ath_dbg(common, MCI, "MCI it's deadbeef, quit mci_reset\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530721 return;
722 }
723
724 /* Program MCI DMA related registers */
725 REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr);
726 REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len);
727 REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr);
728
729 /*
730 * To avoid MCI state machine be affected by incoming remote MCI msgs,
731 * MCI mode will be enabled later, right before reset the MCI TX and RX.
732 */
733
734 regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
735 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
736 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
737 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
738 SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
739 SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |
740 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |
741 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |
742 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
743
744 if (is_2g && (AR_SREV_9462_20(ah)) &&
745 !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
746
747 regval |= SM(1, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
Joe Perchesd2182b62011-12-15 14:55:53 -0800748 ath_dbg(common, MCI, "MCI sched one step look ahead\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530749
750 if (!(mci->config &
751 ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
752
753 thresh = MS(mci->config,
754 ATH_MCI_CONFIG_AGGR_THRESH);
755 thresh &= 7;
756 regval |= SM(1,
757 AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN);
758 regval |= SM(thresh, AR_BTCOEX_CTRL_AGGR_THRESH);
759
760 REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
761 AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
762 REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
763 AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
764
765 } else
Joe Perchesd2182b62011-12-15 14:55:53 -0800766 ath_dbg(common, MCI, "MCI sched aggr thresh: off\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530767 } else
Joe Perchesd2182b62011-12-15 14:55:53 -0800768 ath_dbg(common, MCI, "MCI SCHED one step look ahead off\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530769
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530770 REG_WRITE(ah, AR_BTCOEX_CTRL, regval);
771
772 if (AR_SREV_9462_20(ah)) {
773 REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
774 AR_BTCOEX_CTRL_SPDT_ENABLE);
775 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,
776 AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);
777 }
778
779 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1);
780 REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
781
782 thresh = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);
783 REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, thresh);
784 REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);
785
786 /* Resetting the Rx and Tx paths of MCI */
787 regval = REG_READ(ah, AR_MCI_COMMAND2);
788 regval |= SM(1, AR_MCI_COMMAND2_RESET_TX);
789 REG_WRITE(ah, AR_MCI_COMMAND2, regval);
790
791 udelay(1);
792
793 regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX);
794 REG_WRITE(ah, AR_MCI_COMMAND2, regval);
795
796 if (is_full_sleep) {
797 ar9003_mci_mute_bt(ah);
798 udelay(100);
799 }
800
801 regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
802 REG_WRITE(ah, AR_MCI_COMMAND2, regval);
803 udelay(1);
804 regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
805 REG_WRITE(ah, AR_MCI_COMMAND2, regval);
806
807 ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
808 REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
809 (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
810 SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM)));
811
812 REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
813 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
814
815 if (AR_SREV_9462_20_OR_LATER(ah))
816 ar9003_mci_observation_set_up(ah);
817
818 mci->ready = true;
819 ar9003_mci_prep_interface(ah);
820
821 if (en_int)
822 ar9003_mci_enable_interrupt(ah);
823}
824
Sujith Manoharan528e5d32012-02-22 12:41:12 +0530825void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep)
826{
827 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
828
829 ar9003_mci_disable_interrupt(ah);
830
831 if (mci_hw->ready && !save_fullsleep) {
832 ar9003_mci_mute_bt(ah);
833 udelay(20);
834 REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
835 }
836
837 mci_hw->bt_state = MCI_BT_SLEEP;
838 mci_hw->ready = false;
839}
840
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530841void ar9003_mci_mute_bt(struct ath_hw *ah)
842{
843 struct ath_common *common = ath9k_hw_common(ah);
844
Felix Fietkau8a309302011-12-17 16:47:56 +0100845 if (!ATH9K_HW_CAP_MCI)
846 return;
847
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530848 /* disable all MCI messages */
849 REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
850 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
851 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
852 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
853 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
854 REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
855
856 /* wait pending HW messages to flush out */
857 udelay(10);
858
859 /*
860 * Send LNA_TAKE and SYS_SLEEPING when
861 * 1. reset not after resuming from full sleep
862 * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment
863 */
864
Joe Perchesd2182b62011-12-15 14:55:53 -0800865 ath_dbg(common, MCI, "MCI Send LNA take\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530866 ar9003_mci_send_lna_take(ah, true);
867
868 udelay(5);
869
Joe Perchesd2182b62011-12-15 14:55:53 -0800870 ath_dbg(common, MCI, "MCI Send sys sleeping\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530871 ar9003_mci_send_sys_sleeping(ah, true);
872}
873
874void ar9003_mci_sync_bt_state(struct ath_hw *ah)
875{
876 struct ath_common *common = ath9k_hw_common(ah);
877 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
878 u32 cur_bt_state;
879
Felix Fietkau8a309302011-12-17 16:47:56 +0100880 if (!ATH9K_HW_CAP_MCI)
881 return;
882
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530883 cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
884
885 if (mci->bt_state != cur_bt_state) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800886 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530887 "MCI BT state mismatches. old: %d, new: %d\n",
888 mci->bt_state, cur_bt_state);
889 mci->bt_state = cur_bt_state;
890 }
891
892 if (mci->bt_state != MCI_BT_SLEEP) {
893
894 ar9003_mci_send_coex_version_query(ah, true);
895 ar9003_mci_send_coex_wlan_channels(ah, true);
896
897 if (mci->unhalt_bt_gpm == true) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800898 ath_dbg(common, MCI, "MCI unhalt BT GPM\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530899 ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
900 }
901 }
902}
903
904static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
905{
906 struct ath_common *common = ath9k_hw_common(ah);
907 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
908 u32 new_flags, to_set, to_clear;
909
910 if (AR_SREV_9462_20(ah) &&
911 mci->update_2g5g &&
912 (mci->bt_state != MCI_BT_SLEEP)) {
913
914 if (mci->is_2g) {
915 new_flags = MCI_2G_FLAGS;
916 to_clear = MCI_2G_FLAGS_CLEAR_MASK;
917 to_set = MCI_2G_FLAGS_SET_MASK;
918 } else {
919 new_flags = MCI_5G_FLAGS;
920 to_clear = MCI_5G_FLAGS_CLEAR_MASK;
921 to_set = MCI_5G_FLAGS_SET_MASK;
922 }
923
Joe Perchesd2182b62011-12-15 14:55:53 -0800924 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530925 "MCI BT_MCI_FLAGS: %s 0x%08x clr=0x%08x, set=0x%08x\n",
926 mci->is_2g ? "2G" : "5G", new_flags, to_clear, to_set);
927
928 if (to_clear)
929 ar9003_mci_send_coex_bt_flags(ah, wait_done,
930 MCI_GPM_COEX_BT_FLAGS_CLEAR, to_clear);
931
932 if (to_set)
933 ar9003_mci_send_coex_bt_flags(ah, wait_done,
934 MCI_GPM_COEX_BT_FLAGS_SET, to_set);
935 }
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530936}
937
938static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
939 u32 *payload, bool queue)
940{
941 struct ath_common *common = ath9k_hw_common(ah);
942 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
943 u8 type, opcode;
944
945 if (queue) {
946
947 if (payload)
Joe Perchesd2182b62011-12-15 14:55:53 -0800948 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530949 "MCI ERROR: Send fail: %02x: %02x %02x %02x\n",
950 header,
951 *(((u8 *)payload) + 4),
952 *(((u8 *)payload) + 5),
953 *(((u8 *)payload) + 6));
954 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800955 ath_dbg(common, MCI, "MCI ERROR: Send fail: %02x\n",
956 header);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530957 }
958
959 /* check if the message is to be queued */
960 if (header != MCI_GPM)
961 return;
962
963 type = MCI_GPM_TYPE(payload);
964 opcode = MCI_GPM_OPCODE(payload);
965
966 if (type != MCI_GPM_COEX_AGENT)
967 return;
968
969 switch (opcode) {
970 case MCI_GPM_COEX_BT_UPDATE_FLAGS:
971
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530972 if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) ==
Sujith Manoharanc91ec462012-02-22 12:40:03 +0530973 MCI_GPM_COEX_BT_FLAGS_READ)
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530974 break;
975
976 mci->update_2g5g = queue;
977
978 if (queue)
Joe Perchesd2182b62011-12-15 14:55:53 -0800979 ath_dbg(common, MCI,
980 "MCI BT_MCI_FLAGS: 2G5G status <queued> %s\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530981 mci->is_2g ? "2G" : "5G");
982 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800983 ath_dbg(common, MCI,
984 "MCI BT_MCI_FLAGS: 2G5G status <sent> %s\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530985 mci->is_2g ? "2G" : "5G");
986
987 break;
988
989 case MCI_GPM_COEX_WLAN_CHANNELS:
990
991 mci->wlan_channels_update = queue;
992 if (queue)
Joe Perchesd2182b62011-12-15 14:55:53 -0800993 ath_dbg(common, MCI, "MCI WLAN channel map <queued>\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530994 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800995 ath_dbg(common, MCI, "MCI WLAN channel map <sent>\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530996 break;
997
998 case MCI_GPM_COEX_HALT_BT_GPM:
999
1000 if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
1001 MCI_GPM_COEX_BT_GPM_UNHALT) {
1002
1003 mci->unhalt_bt_gpm = queue;
1004
1005 if (queue)
Joe Perchesd2182b62011-12-15 14:55:53 -08001006 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301007 "MCI UNHALT BT GPM <queued>\n");
1008 else {
1009 mci->halted_bt_gpm = false;
Joe Perchesd2182b62011-12-15 14:55:53 -08001010 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301011 "MCI UNHALT BT GPM <sent>\n");
1012 }
1013 }
1014
1015 if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
1016 MCI_GPM_COEX_BT_GPM_HALT) {
1017
1018 mci->halted_bt_gpm = !queue;
1019
1020 if (queue)
Joe Perchesd2182b62011-12-15 14:55:53 -08001021 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301022 "MCI HALT BT GPM <not sent>\n");
1023 else
Joe Perchesd2182b62011-12-15 14:55:53 -08001024 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301025 "MCI UNHALT BT GPM <sent>\n");
1026 }
1027
1028 break;
1029 default:
1030 break;
1031 }
1032}
1033
1034void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
1035{
1036 struct ath_common *common = ath9k_hw_common(ah);
1037 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
1038
Felix Fietkau8a309302011-12-17 16:47:56 +01001039 if (!ATH9K_HW_CAP_MCI)
1040 return;
1041
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301042 if (mci->update_2g5g) {
1043 if (mci->is_2g) {
1044
1045 ar9003_mci_send_2g5g_status(ah, true);
Joe Perchesd2182b62011-12-15 14:55:53 -08001046 ath_dbg(common, MCI, "MCI Send LNA trans\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301047 ar9003_mci_send_lna_transfer(ah, true);
1048 udelay(5);
1049
1050 REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
1051 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
1052
1053 if (AR_SREV_9462_20(ah)) {
1054 REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
1055 AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
1056 if (!(mci->config &
1057 ATH_MCI_CONFIG_DISABLE_OSLA)) {
1058 REG_SET_BIT(ah, AR_BTCOEX_CTRL,
1059 AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
1060 }
1061 }
1062 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -08001063 ath_dbg(common, MCI, "MCI Send LNA take\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301064 ar9003_mci_send_lna_take(ah, true);
1065 udelay(5);
1066
1067 REG_SET_BIT(ah, AR_MCI_TX_CTRL,
1068 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
1069
1070 if (AR_SREV_9462_20(ah)) {
1071 REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
1072 AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
1073 REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
1074 AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
1075 }
1076
1077 ar9003_mci_send_2g5g_status(ah, true);
1078 }
1079 }
1080}
1081
1082bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
1083 u32 *payload, u8 len, bool wait_done,
1084 bool check_bt)
1085{
1086 struct ath_common *common = ath9k_hw_common(ah);
1087 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
1088 bool msg_sent = false;
1089 u32 regval;
1090 u32 saved_mci_int_en;
1091 int i;
1092
Felix Fietkau8a309302011-12-17 16:47:56 +01001093 if (!ATH9K_HW_CAP_MCI)
1094 return false;
1095
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301096 saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
1097 regval = REG_READ(ah, AR_BTCOEX_CTRL);
1098
1099 if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) {
1100
Joe Perchesd2182b62011-12-15 14:55:53 -08001101 ath_dbg(common, MCI,
1102 "MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n",
1103 header,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301104 (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0);
1105
1106 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
1107 return false;
1108
1109 } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) {
1110
Joe Perchesd2182b62011-12-15 14:55:53 -08001111 ath_dbg(common, MCI,
1112 "MCI Don't send message 0x%x. BT is in sleep state\n",
1113 header);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301114
1115 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
1116 return false;
1117 }
1118
1119 if (wait_done)
1120 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
1121
1122 /* Need to clear SW_MSG_DONE raw bit before wait */
1123
1124 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
1125 (AR_MCI_INTERRUPT_SW_MSG_DONE |
1126 AR_MCI_INTERRUPT_MSG_FAIL_MASK));
1127
1128 if (payload) {
1129 for (i = 0; (i * 4) < len; i++)
1130 REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4),
1131 *(payload + i));
1132 }
1133
1134 REG_WRITE(ah, AR_MCI_COMMAND0,
1135 (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP),
1136 AR_MCI_COMMAND0_DISABLE_TIMESTAMP) |
1137 SM(len, AR_MCI_COMMAND0_LEN) |
1138 SM(header, AR_MCI_COMMAND0_HEADER)));
1139
1140 if (wait_done &&
1141 !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW,
1142 AR_MCI_INTERRUPT_SW_MSG_DONE, 500)))
1143 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
1144 else {
1145 ar9003_mci_queue_unsent_gpm(ah, header, payload, false);
1146 msg_sent = true;
1147 }
1148
1149 if (wait_done)
1150 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
1151
1152 return msg_sent;
1153}
1154EXPORT_SYMBOL(ar9003_mci_send_message);
1155
Sujith Manoharanf2f408e2012-02-22 12:41:06 +05301156void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
1157{
1158 struct ath_common *common = ath9k_hw_common(ah);
1159 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
1160 u32 pld[4] = {0, 0, 0, 0};
1161
1162 if ((mci_hw->bt_state != MCI_BT_AWAKE) ||
1163 (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))
1164 return;
1165
1166 /* send CAL_REQ only when BT is AWAKE. */
1167 ath_dbg(common, MCI, "MCI send WLAN_CAL_REQ 0x%x\n",
1168 mci_hw->wlan_cal_seq);
1169
1170 MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
1171 pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
1172
1173 ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
1174
1175 /* Wait BT_CAL_GRANT for 50ms */
1176 ath_dbg(common, MCI, "MCI wait for BT_CAL_GRANT\n");
1177
1178 if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
1179 ath_dbg(common, MCI, "MCI got BT_CAL_GRANT\n");
1180 } else {
1181 is_reusable = false;
1182 ath_dbg(common, MCI, "MCI BT is not responding\n");
1183 }
1184}
1185
1186void ar9003_mci_init_cal_done(struct ath_hw *ah)
1187{
1188 struct ath_common *common = ath9k_hw_common(ah);
1189 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
1190 u32 pld[4] = {0, 0, 0, 0};
1191
1192 if ((mci_hw->bt_state != MCI_BT_AWAKE) ||
1193 (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))
1194 return;
1195
1196 ath_dbg(common, MCI, "MCI Send WLAN_CAL_DONE 0x%x\n",
1197 mci_hw->wlan_cal_done);
1198
1199 MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
1200 pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
1201 ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
1202}
1203
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301204void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
1205 u16 len, u32 sched_addr)
1206{
1207 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301208
Felix Fietkau8a309302011-12-17 16:47:56 +01001209 if (!ATH9K_HW_CAP_MCI)
1210 return;
1211
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301212 mci->gpm_addr = gpm_addr;
1213 mci->gpm_buf = gpm_buf;
1214 mci->gpm_len = len;
1215 mci->sched_addr = sched_addr;
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301216
1217 ar9003_mci_reset(ah, true, true, true);
1218}
1219EXPORT_SYMBOL(ar9003_mci_setup);
1220
1221void ar9003_mci_cleanup(struct ath_hw *ah)
1222{
Felix Fietkau8a309302011-12-17 16:47:56 +01001223 if (!ATH9K_HW_CAP_MCI)
1224 return;
1225
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301226 /* Turn off MCI and Jupiter mode. */
1227 REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301228 ar9003_mci_disable_interrupt(ah);
1229}
1230EXPORT_SYMBOL(ar9003_mci_cleanup);
1231
1232static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type,
1233 u8 gpm_opcode, u32 *p_gpm)
1234{
1235 struct ath_common *common = ath9k_hw_common(ah);
1236 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
1237 u8 *p_data = (u8 *) p_gpm;
1238
1239 if (gpm_type != MCI_GPM_COEX_AGENT)
1240 return;
1241
1242 switch (gpm_opcode) {
1243 case MCI_GPM_COEX_VERSION_QUERY:
Joe Perchesd2182b62011-12-15 14:55:53 -08001244 ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301245 ar9003_mci_send_coex_version_response(ah, true);
1246 break;
1247 case MCI_GPM_COEX_VERSION_RESPONSE:
Joe Perchesd2182b62011-12-15 14:55:53 -08001248 ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301249 mci->bt_ver_major =
1250 *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION);
1251 mci->bt_ver_minor =
1252 *(p_data + MCI_GPM_COEX_B_MINOR_VERSION);
1253 mci->bt_version_known = true;
Joe Perchesd2182b62011-12-15 14:55:53 -08001254 ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n",
1255 mci->bt_ver_major, mci->bt_ver_minor);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301256 break;
1257 case MCI_GPM_COEX_STATUS_QUERY:
Joe Perchesd2182b62011-12-15 14:55:53 -08001258 ath_dbg(common, MCI,
1259 "MCI Recv GPM COEX Status Query = 0x%02X\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301260 *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP));
1261 mci->wlan_channels_update = true;
1262 ar9003_mci_send_coex_wlan_channels(ah, true);
1263 break;
1264 case MCI_GPM_COEX_BT_PROFILE_INFO:
1265 mci->query_bt = true;
Joe Perchesd2182b62011-12-15 14:55:53 -08001266 ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301267 break;
1268 case MCI_GPM_COEX_BT_STATUS_UPDATE:
1269 mci->query_bt = true;
Joe Perchesd2182b62011-12-15 14:55:53 -08001270 ath_dbg(common, MCI,
1271 "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n",
1272 *(p_gpm + 3));
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301273 break;
1274 default:
1275 break;
1276 }
1277}
1278
1279u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
1280 u8 gpm_opcode, int time_out)
1281{
1282 struct ath_common *common = ath9k_hw_common(ah);
1283 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
1284 u32 *p_gpm = NULL, mismatch = 0, more_data;
1285 u32 offset;
1286 u8 recv_type = 0, recv_opcode = 0;
1287 bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE);
1288
Felix Fietkau8a309302011-12-17 16:47:56 +01001289 if (!ATH9K_HW_CAP_MCI)
1290 return 0;
1291
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301292 more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE;
1293
1294 while (time_out > 0) {
1295 if (p_gpm) {
1296 MCI_GPM_RECYCLE(p_gpm);
1297 p_gpm = NULL;
1298 }
1299
1300 if (more_data != MCI_GPM_MORE)
1301 time_out = ar9003_mci_wait_for_interrupt(ah,
1302 AR_MCI_INTERRUPT_RX_MSG_RAW,
1303 AR_MCI_INTERRUPT_RX_MSG_GPM,
1304 time_out);
1305
1306 if (!time_out)
1307 break;
1308
1309 offset = ar9003_mci_state(ah,
1310 MCI_STATE_NEXT_GPM_OFFSET, &more_data);
1311
1312 if (offset == MCI_GPM_INVALID)
1313 continue;
1314
1315 p_gpm = (u32 *) (mci->gpm_buf + offset);
1316 recv_type = MCI_GPM_TYPE(p_gpm);
1317 recv_opcode = MCI_GPM_OPCODE(p_gpm);
1318
1319 if (MCI_GPM_IS_CAL_TYPE(recv_type)) {
1320
1321 if (recv_type == gpm_type) {
1322
1323 if ((gpm_type == MCI_GPM_BT_CAL_DONE) &&
1324 !b_is_bt_cal_done) {
1325 gpm_type = MCI_GPM_BT_CAL_GRANT;
Joe Perchesd2182b62011-12-15 14:55:53 -08001326 ath_dbg(common, MCI,
1327 "MCI Recv BT_CAL_DONE wait BT_CAL_GRANT\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301328 continue;
1329 }
1330
1331 break;
1332 }
1333 } else if ((recv_type == gpm_type) &&
1334 (recv_opcode == gpm_opcode))
1335 break;
1336
1337 /* not expected message */
1338
1339 /*
1340 * check if it's cal_grant
1341 *
1342 * When we're waiting for cal_grant in reset routine,
1343 * it's possible that BT sends out cal_request at the
1344 * same time. Since BT's calibration doesn't happen
1345 * that often, we'll let BT completes calibration then
1346 * we continue to wait for cal_grant from BT.
1347 * Orginal: Wait BT_CAL_GRANT.
1348 * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait
1349 * BT_CAL_DONE -> Wait BT_CAL_GRANT.
1350 */
1351
1352 if ((gpm_type == MCI_GPM_BT_CAL_GRANT) &&
1353 (recv_type == MCI_GPM_BT_CAL_REQ)) {
1354
1355 u32 payload[4] = {0, 0, 0, 0};
1356
1357 gpm_type = MCI_GPM_BT_CAL_DONE;
Joe Perchesd2182b62011-12-15 14:55:53 -08001358 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301359 "MCI Rcv BT_CAL_REQ, send WLAN_CAL_GRANT\n");
1360
1361 MCI_GPM_SET_CAL_TYPE(payload,
1362 MCI_GPM_WLAN_CAL_GRANT);
1363
1364 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
1365 false, false);
1366
Joe Perchesd2182b62011-12-15 14:55:53 -08001367 ath_dbg(common, MCI, "MCI now wait for BT_CAL_DONE\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301368
1369 continue;
1370 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -08001371 ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n",
1372 *(p_gpm + 1));
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301373 mismatch++;
1374 ar9003_mci_process_gpm_extra(ah, recv_type,
1375 recv_opcode, p_gpm);
1376 }
1377 }
1378 if (p_gpm) {
1379 MCI_GPM_RECYCLE(p_gpm);
1380 p_gpm = NULL;
1381 }
1382
1383 if (time_out <= 0) {
1384 time_out = 0;
Joe Perchesd2182b62011-12-15 14:55:53 -08001385 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301386 "MCI GPM received timeout, mismatch = %d\n", mismatch);
1387 } else
Joe Perchesd2182b62011-12-15 14:55:53 -08001388 ath_dbg(common, MCI, "MCI Receive GPM type=0x%x, code=0x%x\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301389 gpm_type, gpm_opcode);
1390
1391 while (more_data == MCI_GPM_MORE) {
1392
Joe Perchesd2182b62011-12-15 14:55:53 -08001393 ath_dbg(common, MCI, "MCI discard remaining GPM\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301394 offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
1395 &more_data);
1396
1397 if (offset == MCI_GPM_INVALID)
1398 break;
1399
1400 p_gpm = (u32 *) (mci->gpm_buf + offset);
1401 recv_type = MCI_GPM_TYPE(p_gpm);
1402 recv_opcode = MCI_GPM_OPCODE(p_gpm);
1403
1404 if (!MCI_GPM_IS_CAL_TYPE(recv_type))
1405 ar9003_mci_process_gpm_extra(ah, recv_type,
1406 recv_opcode, p_gpm);
1407
1408 MCI_GPM_RECYCLE(p_gpm);
1409 }
1410
1411 return time_out;
1412}
1413
1414u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
1415{
1416 struct ath_common *common = ath9k_hw_common(ah);
1417 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
1418 u32 value = 0, more_gpm = 0, gpm_ptr;
1419 u8 query_type;
1420
Felix Fietkau8a309302011-12-17 16:47:56 +01001421 if (!ATH9K_HW_CAP_MCI)
1422 return 0;
1423
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301424 switch (state_type) {
1425 case MCI_STATE_ENABLE:
1426 if (mci->ready) {
1427
1428 value = REG_READ(ah, AR_BTCOEX_CTRL);
1429
1430 if ((value == 0xdeadbeef) || (value == 0xffffffff))
1431 value = 0;
1432 }
1433 value &= AR_BTCOEX_CTRL_MCI_MODE_EN;
1434 break;
1435 case MCI_STATE_INIT_GPM_OFFSET:
1436 value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
Joe Perchesd2182b62011-12-15 14:55:53 -08001437 ath_dbg(common, MCI, "MCI GPM initial WRITE_PTR=%d\n", value);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301438 mci->gpm_idx = value;
1439 break;
1440 case MCI_STATE_NEXT_GPM_OFFSET:
1441 case MCI_STATE_LAST_GPM_OFFSET:
1442 /*
1443 * This could be useful to avoid new GPM message interrupt which
1444 * may lead to spurious interrupt after power sleep, or multiple
1445 * entry of ath_mci_intr().
1446 * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
1447 * alleviate this effect, but clearing GPM RX interrupt bit is
1448 * safe, because whether this is called from hw or driver code
1449 * there must be an interrupt bit set/triggered initially
1450 */
1451 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
1452 AR_MCI_INTERRUPT_RX_MSG_GPM);
1453
1454 gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
1455 value = gpm_ptr;
1456
1457 if (value == 0)
1458 value = mci->gpm_len - 1;
1459 else if (value >= mci->gpm_len) {
1460 if (value != 0xFFFF) {
1461 value = 0;
Joe Perchesd2182b62011-12-15 14:55:53 -08001462 ath_dbg(common, MCI,
1463 "MCI GPM offset out of range\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301464 }
1465 } else
1466 value--;
1467
1468 if (value == 0xFFFF) {
1469 value = MCI_GPM_INVALID;
1470 more_gpm = MCI_GPM_NOMORE;
Joe Perchesd2182b62011-12-15 14:55:53 -08001471 ath_dbg(common, MCI,
1472 "MCI GPM ptr invalid @ptr=%d, offset=%d, more=GPM_NOMORE\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301473 gpm_ptr, value);
1474 } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
1475
1476 if (gpm_ptr == mci->gpm_idx) {
1477 value = MCI_GPM_INVALID;
1478 more_gpm = MCI_GPM_NOMORE;
1479
Joe Perchesd2182b62011-12-15 14:55:53 -08001480 ath_dbg(common, MCI,
1481 "MCI GPM message not available @ptr=%d, @offset=%d, more=GPM_NOMORE\n",
1482 gpm_ptr, value);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301483 } else {
1484 for (;;) {
1485
1486 u32 temp_index;
1487
1488 /* skip reserved GPM if any */
1489
1490 if (value != mci->gpm_idx)
1491 more_gpm = MCI_GPM_MORE;
1492 else
1493 more_gpm = MCI_GPM_NOMORE;
1494
1495 temp_index = mci->gpm_idx;
1496 mci->gpm_idx++;
1497
1498 if (mci->gpm_idx >=
1499 mci->gpm_len)
1500 mci->gpm_idx = 0;
1501
Joe Perchesd2182b62011-12-15 14:55:53 -08001502 ath_dbg(common, MCI,
1503 "MCI GPM message got ptr=%d, @offset=%d, more=%d\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301504 gpm_ptr, temp_index,
1505 (more_gpm == MCI_GPM_MORE));
1506
1507 if (ar9003_mci_is_gpm_valid(ah,
1508 temp_index)) {
1509 value = temp_index;
1510 break;
1511 }
1512
1513 if (more_gpm == MCI_GPM_NOMORE) {
1514 value = MCI_GPM_INVALID;
1515 break;
1516 }
1517 }
1518 }
1519 if (p_data)
1520 *p_data = more_gpm;
1521 }
1522
1523 if (value != MCI_GPM_INVALID)
1524 value <<= 4;
1525
1526 break;
1527 case MCI_STATE_LAST_SCHD_MSG_OFFSET:
1528 value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
1529 AR_MCI_RX_LAST_SCHD_MSG_INDEX);
1530 /* Make it in bytes */
1531 value <<= 4;
1532 break;
1533
1534 case MCI_STATE_REMOTE_SLEEP:
1535 value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
1536 AR_MCI_RX_REMOTE_SLEEP) ?
1537 MCI_BT_SLEEP : MCI_BT_AWAKE;
1538 break;
1539
1540 case MCI_STATE_CONT_RSSI_POWER:
1541 value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
1542 break;
1543
1544 case MCI_STATE_CONT_PRIORITY:
1545 value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
1546 break;
1547
1548 case MCI_STATE_CONT_TXRX:
1549 value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
1550 break;
1551
1552 case MCI_STATE_BT:
1553 value = mci->bt_state;
1554 break;
1555
1556 case MCI_STATE_SET_BT_SLEEP:
1557 mci->bt_state = MCI_BT_SLEEP;
1558 break;
1559
1560 case MCI_STATE_SET_BT_AWAKE:
1561 mci->bt_state = MCI_BT_AWAKE;
1562 ar9003_mci_send_coex_version_query(ah, true);
1563 ar9003_mci_send_coex_wlan_channels(ah, true);
1564
1565 if (mci->unhalt_bt_gpm) {
1566
Joe Perchesd2182b62011-12-15 14:55:53 -08001567 ath_dbg(common, MCI, "MCI unhalt BT GPM\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301568 ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
1569 }
1570
1571 ar9003_mci_2g5g_switch(ah, true);
1572 break;
1573
1574 case MCI_STATE_SET_BT_CAL_START:
1575 mci->bt_state = MCI_BT_CAL_START;
1576 break;
1577
1578 case MCI_STATE_SET_BT_CAL:
1579 mci->bt_state = MCI_BT_CAL;
1580 break;
1581
1582 case MCI_STATE_RESET_REQ_WAKE:
1583 ar9003_mci_reset_req_wakeup(ah);
1584 mci->update_2g5g = true;
1585
1586 if ((AR_SREV_9462_20_OR_LATER(ah)) &&
1587 (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK)) {
1588 /* Check if we still have control of the GPIOs */
1589 if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) &
1590 ATH_MCI_CONFIG_MCI_OBS_GPIO) !=
1591 ATH_MCI_CONFIG_MCI_OBS_GPIO) {
1592
Joe Perchesd2182b62011-12-15 14:55:53 -08001593 ath_dbg(common, MCI,
1594 "MCI reconfigure observation\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301595 ar9003_mci_observation_set_up(ah);
1596 }
1597 }
1598 break;
1599
1600 case MCI_STATE_SEND_WLAN_COEX_VERSION:
1601 ar9003_mci_send_coex_version_response(ah, true);
1602 break;
1603
1604 case MCI_STATE_SET_BT_COEX_VERSION:
1605
1606 if (!p_data)
Joe Perchesd2182b62011-12-15 14:55:53 -08001607 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301608 "MCI Set BT Coex version with NULL data!!\n");
1609 else {
1610 mci->bt_ver_major = (*p_data >> 8) & 0xff;
1611 mci->bt_ver_minor = (*p_data) & 0xff;
1612 mci->bt_version_known = true;
Joe Perchesd2182b62011-12-15 14:55:53 -08001613 ath_dbg(common, MCI, "MCI BT version set: %d.%d\n",
1614 mci->bt_ver_major, mci->bt_ver_minor);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301615 }
1616 break;
1617
1618 case MCI_STATE_SEND_WLAN_CHANNELS:
1619 if (p_data) {
1620 if (((mci->wlan_channels[1] & 0xffff0000) ==
1621 (*(p_data + 1) & 0xffff0000)) &&
1622 (mci->wlan_channels[2] == *(p_data + 2)) &&
1623 (mci->wlan_channels[3] == *(p_data + 3)))
1624 break;
1625
1626 mci->wlan_channels[0] = *p_data++;
1627 mci->wlan_channels[1] = *p_data++;
1628 mci->wlan_channels[2] = *p_data++;
1629 mci->wlan_channels[3] = *p_data++;
1630 }
1631 mci->wlan_channels_update = true;
1632 ar9003_mci_send_coex_wlan_channels(ah, true);
1633 break;
1634
1635 case MCI_STATE_SEND_VERSION_QUERY:
1636 ar9003_mci_send_coex_version_query(ah, true);
1637 break;
1638
1639 case MCI_STATE_SEND_STATUS_QUERY:
Sujith Manoharanc91ec462012-02-22 12:40:03 +05301640 query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301641
1642 ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
1643 break;
1644
1645 case MCI_STATE_NEED_FLUSH_BT_INFO:
1646 /*
1647 * btcoex_hw.mci.unhalt_bt_gpm means whether it's
1648 * needed to send UNHALT message. It's set whenever
1649 * there's a request to send HALT message.
1650 * mci_halted_bt_gpm means whether HALT message is sent
1651 * out successfully.
1652 *
1653 * Checking (mci_unhalt_bt_gpm == false) instead of
1654 * checking (ah->mci_halted_bt_gpm == false) will make
1655 * sure currently is in UNHALT-ed mode and BT can
1656 * respond to status query.
1657 */
1658 value = (!mci->unhalt_bt_gpm &&
1659 mci->need_flush_btinfo) ? 1 : 0;
1660 if (p_data)
1661 mci->need_flush_btinfo =
1662 (*p_data != 0) ? true : false;
1663 break;
1664
1665 case MCI_STATE_RECOVER_RX:
1666
Joe Perchesd2182b62011-12-15 14:55:53 -08001667 ath_dbg(common, MCI, "MCI hw RECOVER_RX\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301668 ar9003_mci_prep_interface(ah);
1669 mci->query_bt = true;
1670 mci->need_flush_btinfo = true;
1671 ar9003_mci_send_coex_wlan_channels(ah, true);
1672 ar9003_mci_2g5g_switch(ah, true);
1673 break;
1674
1675 case MCI_STATE_NEED_FTP_STOMP:
1676 value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
1677 break;
1678
1679 case MCI_STATE_NEED_TUNING:
1680 value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
1681 break;
1682
1683 default:
1684 break;
1685
1686 }
1687
1688 return value;
1689}
1690EXPORT_SYMBOL(ar9003_mci_state);