blob: 65db2cd44c9a0e9acfd0f46d153daed19db0e95c [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"
19#include "ar9003_phy.h"
20#include "ar9003_mci.h"
21
22static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah)
23{
24 if (!AR_SREV_9462_20(ah))
25 return;
26
27 REG_RMW_FIELD(ah, AR_MCI_COMMAND2,
28 AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 1);
29 udelay(1);
30 REG_RMW_FIELD(ah, AR_MCI_COMMAND2,
31 AR_MCI_COMMAND2_RESET_REQ_WAKEUP, 0);
32}
33
34static int ar9003_mci_wait_for_interrupt(struct ath_hw *ah, u32 address,
35 u32 bit_position, int time_out)
36{
37 struct ath_common *common = ath9k_hw_common(ah);
38
39 while (time_out) {
40
41 if (REG_READ(ah, address) & bit_position) {
42
43 REG_WRITE(ah, address, bit_position);
44
45 if (address == AR_MCI_INTERRUPT_RX_MSG_RAW) {
46
47 if (bit_position &
48 AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)
49 ar9003_mci_reset_req_wakeup(ah);
50
51 if (bit_position &
52 (AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING |
53 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING))
54 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
55 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
56
57 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
58 AR_MCI_INTERRUPT_RX_MSG);
59 }
60 break;
61 }
62
63 udelay(10);
64 time_out -= 10;
65
66 if (time_out < 0)
67 break;
68 }
69
70 if (time_out <= 0) {
Joe Perchesd2182b62011-12-15 14:55:53 -080071 ath_dbg(common, MCI,
72 "MCI Wait for Reg 0x%08x = 0x%08x timeout\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +053073 address, bit_position);
Joe Perchesd2182b62011-12-15 14:55:53 -080074 ath_dbg(common, MCI,
75 "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +053076 REG_READ(ah, AR_MCI_INTERRUPT_RAW),
77 REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW));
78 time_out = 0;
79 }
80
81 return time_out;
82}
83
84void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done)
85{
86 u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00};
87
Felix Fietkau8a309302011-12-17 16:47:56 +010088 if (!ATH9K_HW_CAP_MCI)
89 return;
90
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +053091 ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16,
92 wait_done, false);
93 udelay(5);
94}
95
96void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done)
97{
98 u32 payload = 0x00000000;
99
Felix Fietkau8a309302011-12-17 16:47:56 +0100100 if (!ATH9K_HW_CAP_MCI)
101 return;
102
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530103 ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1,
104 wait_done, false);
105}
106
107static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done)
108{
109 ar9003_mci_send_message(ah, MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP,
110 NULL, 0, wait_done, false);
111 udelay(5);
112}
113
114void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done)
115{
Felix Fietkau8a309302011-12-17 16:47:56 +0100116 if (!ATH9K_HW_CAP_MCI)
117 return;
118
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530119 ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP,
120 NULL, 0, wait_done, false);
121}
122
123static void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done)
124{
125 u32 payload = 0x70000000;
126
127 ar9003_mci_send_message(ah, MCI_LNA_TAKE, 0, &payload, 1,
128 wait_done, false);
129}
130
131static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done)
132{
133 ar9003_mci_send_message(ah, MCI_SYS_SLEEPING,
134 MCI_FLAG_DISABLE_TIMESTAMP,
135 NULL, 0, wait_done, false);
136}
137
138static void ar9003_mci_send_coex_version_query(struct ath_hw *ah,
139 bool wait_done)
140{
141 struct ath_common *common = ath9k_hw_common(ah);
142 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
143 u32 payload[4] = {0, 0, 0, 0};
144
145 if (!mci->bt_version_known &&
146 (mci->bt_state != MCI_BT_SLEEP)) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800147 ath_dbg(common, MCI, "MCI Send Coex version query\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530148 MCI_GPM_SET_TYPE_OPCODE(payload,
149 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_VERSION_QUERY);
150 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
151 wait_done, true);
152 }
153}
154
155static void ar9003_mci_send_coex_version_response(struct ath_hw *ah,
156 bool wait_done)
157{
158 struct ath_common *common = ath9k_hw_common(ah);
159 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
160 u32 payload[4] = {0, 0, 0, 0};
161
Joe Perchesd2182b62011-12-15 14:55:53 -0800162 ath_dbg(common, MCI, "MCI Send Coex version response\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530163 MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT,
164 MCI_GPM_COEX_VERSION_RESPONSE);
165 *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) =
166 mci->wlan_ver_major;
167 *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) =
168 mci->wlan_ver_minor;
169 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
170}
171
172static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah,
173 bool wait_done)
174{
175 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
176 u32 *payload = &mci->wlan_channels[0];
177
178 if ((mci->wlan_channels_update == true) &&
179 (mci->bt_state != MCI_BT_SLEEP)) {
180 MCI_GPM_SET_TYPE_OPCODE(payload,
181 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_WLAN_CHANNELS);
182 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
183 wait_done, true);
184 MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff);
185 }
186}
187
188static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah,
189 bool wait_done, u8 query_type)
190{
191 struct ath_common *common = ath9k_hw_common(ah);
192 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
193 u32 payload[4] = {0, 0, 0, 0};
194 bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO |
195 MCI_GPM_COEX_QUERY_BT_TOPOLOGY));
196
197 if (mci->bt_state != MCI_BT_SLEEP) {
198
Joe Perchesd2182b62011-12-15 14:55:53 -0800199 ath_dbg(common, MCI, "MCI Send Coex BT Status Query 0x%02X\n",
200 query_type);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530201
202 MCI_GPM_SET_TYPE_OPCODE(payload,
203 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_STATUS_QUERY);
204
205 *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type;
206 /*
207 * If bt_status_query message is not sent successfully,
208 * then need_flush_btinfo should be set again.
209 */
210 if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
211 wait_done, true)) {
212 if (query_btinfo) {
213 mci->need_flush_btinfo = true;
214
Joe Perchesd2182b62011-12-15 14:55:53 -0800215 ath_dbg(common, MCI,
216 "MCI send bt_status_query fail, set flush flag again\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530217 }
218 }
219
220 if (query_btinfo)
221 mci->query_bt = false;
222 }
223}
224
225void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt,
226 bool wait_done)
227{
228 struct ath_common *common = ath9k_hw_common(ah);
229 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
230 u32 payload[4] = {0, 0, 0, 0};
231
Felix Fietkau8a309302011-12-17 16:47:56 +0100232 if (!ATH9K_HW_CAP_MCI)
233 return;
234
Joe Perchesd2182b62011-12-15 14:55:53 -0800235 ath_dbg(common, MCI, "MCI Send Coex %s BT GPM\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530236 (halt) ? "halt" : "unhalt");
237
238 MCI_GPM_SET_TYPE_OPCODE(payload,
239 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_HALT_BT_GPM);
240
241 if (halt) {
242 mci->query_bt = true;
243 /* Send next unhalt no matter halt sent or not */
244 mci->unhalt_bt_gpm = true;
245 mci->need_flush_btinfo = true;
246 *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) =
247 MCI_GPM_COEX_BT_GPM_HALT;
248 } else
249 *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) =
250 MCI_GPM_COEX_BT_GPM_UNHALT;
251
252 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true);
253}
254
255
256static void ar9003_mci_prep_interface(struct ath_hw *ah)
257{
258 struct ath_common *common = ath9k_hw_common(ah);
259 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
260 u32 saved_mci_int_en;
261 u32 mci_timeout = 150;
262
263 mci->bt_state = MCI_BT_SLEEP;
264 saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
265
266 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
267 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
268 REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW));
269 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
270 REG_READ(ah, AR_MCI_INTERRUPT_RAW));
271
272 /* Remote Reset */
Joe Perchesd2182b62011-12-15 14:55:53 -0800273 ath_dbg(common, MCI, "MCI Reset sequence start\n");
274 ath_dbg(common, MCI, "MCI send REMOTE_RESET\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530275 ar9003_mci_remote_reset(ah, true);
276
Joe Perchesd2182b62011-12-15 14:55:53 -0800277 ath_dbg(common, MCI, "MCI Send REQ_WAKE to remoter(BT)\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530278 ar9003_mci_send_req_wake(ah, true);
279
280 if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
281 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) {
282
Joe Perchesd2182b62011-12-15 14:55:53 -0800283 ath_dbg(common, MCI, "MCI SYS_WAKING from remote(BT)\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530284 mci->bt_state = MCI_BT_AWAKE;
285
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530286 /*
287 * we don't need to send more remote_reset at this moment.
288 * If BT receive first remote_reset, then BT HW will
289 * be cleaned up and will be able to receive req_wake
290 * and BT HW will respond sys_waking.
291 * In this case, WLAN will receive BT's HW sys_waking.
292 * Otherwise, if BT SW missed initial remote_reset,
293 * that remote_reset will still clean up BT MCI RX,
294 * and the req_wake will wake BT up,
295 * and BT SW will respond this req_wake with a remote_reset and
296 * sys_waking. In this case, WLAN will receive BT's SW
297 * sys_waking. In either case, BT's RX is cleaned up. So we
298 * don't need to reply BT's remote_reset now, if any.
299 * Similarly, if in any case, WLAN can receive BT's sys_waking,
300 * that means WLAN's RX is also fine.
301 */
302
303 /* Send SYS_WAKING to BT */
304
Joe Perchesd2182b62011-12-15 14:55:53 -0800305 ath_dbg(common, MCI, "MCI send SW SYS_WAKING to remote BT\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530306
307 ar9003_mci_send_sys_waking(ah, true);
308 udelay(10);
309
310 /*
311 * Set BT priority interrupt value to be 0xff to
312 * avoid having too many BT PRIORITY interrupts.
313 */
314
315 REG_WRITE(ah, AR_MCI_BT_PRI0, 0xFFFFFFFF);
316 REG_WRITE(ah, AR_MCI_BT_PRI1, 0xFFFFFFFF);
317 REG_WRITE(ah, AR_MCI_BT_PRI2, 0xFFFFFFFF);
318 REG_WRITE(ah, AR_MCI_BT_PRI3, 0xFFFFFFFF);
319 REG_WRITE(ah, AR_MCI_BT_PRI, 0X000000FF);
320
321 /*
322 * A contention reset will be received after send out
323 * sys_waking. Also BT priority interrupt bits will be set.
324 * Clear those bits before the next step.
325 */
326
327 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
328 AR_MCI_INTERRUPT_RX_MSG_CONT_RST);
329 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
330 AR_MCI_INTERRUPT_BT_PRI);
331
Sujith Manoharanc91ec462012-02-22 12:40:03 +0530332 if (mci->is_2g) {
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530333 /* Send LNA_TRANS */
Joe Perchesd2182b62011-12-15 14:55:53 -0800334 ath_dbg(common, MCI, "MCI send LNA_TRANS to BT\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530335 ar9003_mci_send_lna_transfer(ah, true);
336 udelay(5);
337 }
338
Sujith Manoharanc91ec462012-02-22 12:40:03 +0530339 if ((mci->is_2g && !mci->update_2g5g)) {
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530340 if (ar9003_mci_wait_for_interrupt(ah,
341 AR_MCI_INTERRUPT_RX_MSG_RAW,
342 AR_MCI_INTERRUPT_RX_MSG_LNA_INFO,
343 mci_timeout))
Joe Perchesd2182b62011-12-15 14:55:53 -0800344 ath_dbg(common, MCI,
345 "MCI WLAN has control over the LNA & BT obeys it\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530346 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800347 ath_dbg(common, MCI,
348 "MCI BT didn't respond to LNA_TRANS\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530349 }
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530350 }
351
352 /* Clear the extra redundant SYS_WAKING from BT */
353 if ((mci->bt_state == MCI_BT_AWAKE) &&
354 (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
355 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) &&
356 (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
357 AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) {
358
359 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
360 AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING);
361 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
362 AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE);
363 }
364
365 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
366}
367
Sujith Manoharand1ca8b82012-02-22 12:41:01 +0530368void ar9003_mci_set_full_sleep(struct ath_hw *ah)
369{
370 struct ath_common *common = ath9k_hw_common(ah);
371 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
372
373 if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
374 (mci->bt_state != MCI_BT_SLEEP) &&
375 !mci->halted_bt_gpm) {
376 ath_dbg(common, MCI,
377 "MCI halt BT GPM (full_sleep)\n");
378 ar9003_mci_send_coex_halt_bt_gpm(ah, true, true);
379 }
380
381 mci->ready = false;
382 REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
383}
384
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530385void ar9003_mci_disable_interrupt(struct ath_hw *ah)
386{
Felix Fietkau8a309302011-12-17 16:47:56 +0100387 if (!ATH9K_HW_CAP_MCI)
388 return;
389
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530390 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
391 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0);
392}
393
394void ar9003_mci_enable_interrupt(struct ath_hw *ah)
395{
Felix Fietkau8a309302011-12-17 16:47:56 +0100396 if (!ATH9K_HW_CAP_MCI)
397 return;
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530398
399 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT);
400 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN,
401 AR_MCI_INTERRUPT_RX_MSG_DEFAULT);
402}
403
404bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints)
405{
406 u32 intr;
407
Felix Fietkau8a309302011-12-17 16:47:56 +0100408 if (!ATH9K_HW_CAP_MCI)
409 return false;
410
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530411 intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
412 return ((intr & ints) == ints);
413}
414
415void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr,
416 u32 *rx_msg_intr)
417{
418 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
Felix Fietkau8a309302011-12-17 16:47:56 +0100419
420 if (!ATH9K_HW_CAP_MCI)
421 return;
422
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530423 *raw_intr = mci->raw_intr;
424 *rx_msg_intr = mci->rx_msg_intr;
425
426 /* Clean int bits after the values are read. */
427 mci->raw_intr = 0;
428 mci->rx_msg_intr = 0;
429}
430EXPORT_SYMBOL(ar9003_mci_get_interrupt);
431
Sujith Manoharan5a1e2732012-02-22 12:40:55 +0530432void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
433{
434 struct ath_common *common = ath9k_hw_common(ah);
435 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
436 u32 raw_intr, rx_msg_intr;
437
438 rx_msg_intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW);
439 raw_intr = REG_READ(ah, AR_MCI_INTERRUPT_RAW);
440
441 if ((raw_intr == 0xdeadbeef) || (rx_msg_intr == 0xdeadbeef)) {
442 ath_dbg(common, MCI,
443 "MCI gets 0xdeadbeef during int processing\n");
444 } else {
445 mci->rx_msg_intr |= rx_msg_intr;
446 mci->raw_intr |= raw_intr;
447 *masked |= ATH9K_INT_MCI;
448
449 if (rx_msg_intr & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO)
450 mci->cont_status = REG_READ(ah, AR_MCI_CONT_STATUS);
451
452 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, rx_msg_intr);
453 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, raw_intr);
454 }
455}
456
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530457void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g)
458{
459 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
460
Felix Fietkau8a309302011-12-17 16:47:56 +0100461 if (!ATH9K_HW_CAP_MCI)
462 return;
463
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530464 if (!mci->update_2g5g &&
465 (mci->is_2g != is_2g))
466 mci->update_2g5g = true;
467
468 mci->is_2g = is_2g;
469}
470
471static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index)
472{
473 struct ath_common *common = ath9k_hw_common(ah);
474 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
475 u32 *payload;
476 u32 recv_type, offset;
477
478 if (msg_index == MCI_GPM_INVALID)
479 return false;
480
481 offset = msg_index << 4;
482
483 payload = (u32 *)(mci->gpm_buf + offset);
484 recv_type = MCI_GPM_TYPE(payload);
485
486 if (recv_type == MCI_GPM_RSVD_PATTERN) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800487 ath_dbg(common, MCI, "MCI Skip RSVD GPM\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530488 return false;
489 }
490
491 return true;
492}
493
494static void ar9003_mci_observation_set_up(struct ath_hw *ah)
495{
496 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
497 if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) {
498
499 ath9k_hw_cfg_output(ah, 3,
500 AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA);
501 ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK);
502 ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
503 ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
504
505 } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) {
506
507 ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX);
508 ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX);
509 ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
510 ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
511 ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
512
513 } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) {
514
515 ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX);
516 ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX);
517 ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA);
518 ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK);
519
520 } else
521 return;
522
523 REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
524
525 if (AR_SREV_9462_20_OR_LATER(ah)) {
526 REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
527 AR_GLB_DS_JTAG_DISABLE, 1);
528 REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL,
529 AR_GLB_WLAN_UART_INTF_EN, 0);
530 REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL,
531 ATH_MCI_CONFIG_MCI_OBS_GPIO);
532 }
533
534 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0);
535 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1);
536 REG_WRITE(ah, AR_OBS, 0x4b);
537 REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03);
538 REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01);
539 REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02);
540 REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03);
541 REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS,
542 AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07);
543}
544
545static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done,
546 u8 opcode, u32 bt_flags)
547{
548 struct ath_common *common = ath9k_hw_common(ah);
549 u32 pld[4] = {0, 0, 0, 0};
550
551 MCI_GPM_SET_TYPE_OPCODE(pld,
552 MCI_GPM_COEX_AGENT, MCI_GPM_COEX_BT_UPDATE_FLAGS);
553
554 *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode;
555 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF;
556 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF;
557 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF;
558 *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF;
559
Joe Perchesd2182b62011-12-15 14:55:53 -0800560 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530561 "MCI BT_MCI_FLAGS: Send Coex BT Update Flags %s 0x%08x\n",
Joe Perchesd2182b62011-12-15 14:55:53 -0800562 opcode == MCI_GPM_COEX_BT_FLAGS_READ ? "READ" :
563 opcode == MCI_GPM_COEX_BT_FLAGS_SET ? "SET" : "CLEAR",
564 bt_flags);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530565
566 return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16,
567 wait_done, true);
568}
569
570void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
571 bool is_full_sleep)
572{
573 struct ath_common *common = ath9k_hw_common(ah);
574 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
575 u32 regval, thresh;
576
Felix Fietkau8a309302011-12-17 16:47:56 +0100577 if (!ATH9K_HW_CAP_MCI)
578 return;
579
Joe Perchesd2182b62011-12-15 14:55:53 -0800580 ath_dbg(common, MCI, "MCI full_sleep = %d, is_2g = %d\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530581 is_full_sleep, is_2g);
582
583 /*
584 * GPM buffer and scheduling message buffer are not allocated
585 */
586
587 if (!mci->gpm_addr && !mci->sched_addr) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800588 ath_dbg(common, MCI,
589 "MCI GPM and schedule buffers are not allocated\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530590 return;
591 }
592
593 if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800594 ath_dbg(common, MCI, "MCI it's deadbeef, quit mci_reset\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530595 return;
596 }
597
598 /* Program MCI DMA related registers */
599 REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr);
600 REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len);
601 REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr);
602
603 /*
604 * To avoid MCI state machine be affected by incoming remote MCI msgs,
605 * MCI mode will be enabled later, right before reset the MCI TX and RX.
606 */
607
608 regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) |
609 SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) |
610 SM(1, AR_BTCOEX_CTRL_PA_SHARED) |
611 SM(1, AR_BTCOEX_CTRL_LNA_SHARED) |
612 SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) |
613 SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) |
614 SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) |
615 SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) |
616 SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
617
618 if (is_2g && (AR_SREV_9462_20(ah)) &&
619 !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) {
620
621 regval |= SM(1, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
Joe Perchesd2182b62011-12-15 14:55:53 -0800622 ath_dbg(common, MCI, "MCI sched one step look ahead\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530623
624 if (!(mci->config &
625 ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) {
626
627 thresh = MS(mci->config,
628 ATH_MCI_CONFIG_AGGR_THRESH);
629 thresh &= 7;
630 regval |= SM(1,
631 AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN);
632 regval |= SM(thresh, AR_BTCOEX_CTRL_AGGR_THRESH);
633
634 REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
635 AR_MCI_SCHD_TABLE_2_HW_BASED, 1);
636 REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2,
637 AR_MCI_SCHD_TABLE_2_MEM_BASED, 1);
638
639 } else
Joe Perchesd2182b62011-12-15 14:55:53 -0800640 ath_dbg(common, MCI, "MCI sched aggr thresh: off\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530641 } else
Joe Perchesd2182b62011-12-15 14:55:53 -0800642 ath_dbg(common, MCI, "MCI SCHED one step look ahead off\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530643
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530644 REG_WRITE(ah, AR_BTCOEX_CTRL, regval);
645
646 if (AR_SREV_9462_20(ah)) {
647 REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
648 AR_BTCOEX_CTRL_SPDT_ENABLE);
649 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3,
650 AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20);
651 }
652
653 REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1);
654 REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
655
656 thresh = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV);
657 REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, thresh);
658 REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN);
659
660 /* Resetting the Rx and Tx paths of MCI */
661 regval = REG_READ(ah, AR_MCI_COMMAND2);
662 regval |= SM(1, AR_MCI_COMMAND2_RESET_TX);
663 REG_WRITE(ah, AR_MCI_COMMAND2, regval);
664
665 udelay(1);
666
667 regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX);
668 REG_WRITE(ah, AR_MCI_COMMAND2, regval);
669
670 if (is_full_sleep) {
671 ar9003_mci_mute_bt(ah);
672 udelay(100);
673 }
674
675 regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
676 REG_WRITE(ah, AR_MCI_COMMAND2, regval);
677 udelay(1);
678 regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX);
679 REG_WRITE(ah, AR_MCI_COMMAND2, regval);
680
681 ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL);
682 REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE,
683 (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) |
684 SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM)));
685
686 REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
687 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
688
689 if (AR_SREV_9462_20_OR_LATER(ah))
690 ar9003_mci_observation_set_up(ah);
691
692 mci->ready = true;
693 ar9003_mci_prep_interface(ah);
694
695 if (en_int)
696 ar9003_mci_enable_interrupt(ah);
697}
698
699void ar9003_mci_mute_bt(struct ath_hw *ah)
700{
701 struct ath_common *common = ath9k_hw_common(ah);
702
Felix Fietkau8a309302011-12-17 16:47:56 +0100703 if (!ATH9K_HW_CAP_MCI)
704 return;
705
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530706 /* disable all MCI messages */
707 REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000);
708 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff);
709 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff);
710 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff);
711 REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff);
712 REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
713
714 /* wait pending HW messages to flush out */
715 udelay(10);
716
717 /*
718 * Send LNA_TAKE and SYS_SLEEPING when
719 * 1. reset not after resuming from full sleep
720 * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment
721 */
722
Joe Perchesd2182b62011-12-15 14:55:53 -0800723 ath_dbg(common, MCI, "MCI Send LNA take\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530724 ar9003_mci_send_lna_take(ah, true);
725
726 udelay(5);
727
Joe Perchesd2182b62011-12-15 14:55:53 -0800728 ath_dbg(common, MCI, "MCI Send sys sleeping\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530729 ar9003_mci_send_sys_sleeping(ah, true);
730}
731
732void ar9003_mci_sync_bt_state(struct ath_hw *ah)
733{
734 struct ath_common *common = ath9k_hw_common(ah);
735 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
736 u32 cur_bt_state;
737
Felix Fietkau8a309302011-12-17 16:47:56 +0100738 if (!ATH9K_HW_CAP_MCI)
739 return;
740
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530741 cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL);
742
743 if (mci->bt_state != cur_bt_state) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800744 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530745 "MCI BT state mismatches. old: %d, new: %d\n",
746 mci->bt_state, cur_bt_state);
747 mci->bt_state = cur_bt_state;
748 }
749
750 if (mci->bt_state != MCI_BT_SLEEP) {
751
752 ar9003_mci_send_coex_version_query(ah, true);
753 ar9003_mci_send_coex_wlan_channels(ah, true);
754
755 if (mci->unhalt_bt_gpm == true) {
Joe Perchesd2182b62011-12-15 14:55:53 -0800756 ath_dbg(common, MCI, "MCI unhalt BT GPM\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530757 ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
758 }
759 }
760}
761
762static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done)
763{
764 struct ath_common *common = ath9k_hw_common(ah);
765 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
766 u32 new_flags, to_set, to_clear;
767
768 if (AR_SREV_9462_20(ah) &&
769 mci->update_2g5g &&
770 (mci->bt_state != MCI_BT_SLEEP)) {
771
772 if (mci->is_2g) {
773 new_flags = MCI_2G_FLAGS;
774 to_clear = MCI_2G_FLAGS_CLEAR_MASK;
775 to_set = MCI_2G_FLAGS_SET_MASK;
776 } else {
777 new_flags = MCI_5G_FLAGS;
778 to_clear = MCI_5G_FLAGS_CLEAR_MASK;
779 to_set = MCI_5G_FLAGS_SET_MASK;
780 }
781
Joe Perchesd2182b62011-12-15 14:55:53 -0800782 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530783 "MCI BT_MCI_FLAGS: %s 0x%08x clr=0x%08x, set=0x%08x\n",
784 mci->is_2g ? "2G" : "5G", new_flags, to_clear, to_set);
785
786 if (to_clear)
787 ar9003_mci_send_coex_bt_flags(ah, wait_done,
788 MCI_GPM_COEX_BT_FLAGS_CLEAR, to_clear);
789
790 if (to_set)
791 ar9003_mci_send_coex_bt_flags(ah, wait_done,
792 MCI_GPM_COEX_BT_FLAGS_SET, to_set);
793 }
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530794}
795
796static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
797 u32 *payload, bool queue)
798{
799 struct ath_common *common = ath9k_hw_common(ah);
800 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
801 u8 type, opcode;
802
803 if (queue) {
804
805 if (payload)
Joe Perchesd2182b62011-12-15 14:55:53 -0800806 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530807 "MCI ERROR: Send fail: %02x: %02x %02x %02x\n",
808 header,
809 *(((u8 *)payload) + 4),
810 *(((u8 *)payload) + 5),
811 *(((u8 *)payload) + 6));
812 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800813 ath_dbg(common, MCI, "MCI ERROR: Send fail: %02x\n",
814 header);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530815 }
816
817 /* check if the message is to be queued */
818 if (header != MCI_GPM)
819 return;
820
821 type = MCI_GPM_TYPE(payload);
822 opcode = MCI_GPM_OPCODE(payload);
823
824 if (type != MCI_GPM_COEX_AGENT)
825 return;
826
827 switch (opcode) {
828 case MCI_GPM_COEX_BT_UPDATE_FLAGS:
829
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530830 if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) ==
Sujith Manoharanc91ec462012-02-22 12:40:03 +0530831 MCI_GPM_COEX_BT_FLAGS_READ)
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530832 break;
833
834 mci->update_2g5g = queue;
835
836 if (queue)
Joe Perchesd2182b62011-12-15 14:55:53 -0800837 ath_dbg(common, MCI,
838 "MCI BT_MCI_FLAGS: 2G5G status <queued> %s\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530839 mci->is_2g ? "2G" : "5G");
840 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800841 ath_dbg(common, MCI,
842 "MCI BT_MCI_FLAGS: 2G5G status <sent> %s\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530843 mci->is_2g ? "2G" : "5G");
844
845 break;
846
847 case MCI_GPM_COEX_WLAN_CHANNELS:
848
849 mci->wlan_channels_update = queue;
850 if (queue)
Joe Perchesd2182b62011-12-15 14:55:53 -0800851 ath_dbg(common, MCI, "MCI WLAN channel map <queued>\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530852 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800853 ath_dbg(common, MCI, "MCI WLAN channel map <sent>\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530854 break;
855
856 case MCI_GPM_COEX_HALT_BT_GPM:
857
858 if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
859 MCI_GPM_COEX_BT_GPM_UNHALT) {
860
861 mci->unhalt_bt_gpm = queue;
862
863 if (queue)
Joe Perchesd2182b62011-12-15 14:55:53 -0800864 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530865 "MCI UNHALT BT GPM <queued>\n");
866 else {
867 mci->halted_bt_gpm = false;
Joe Perchesd2182b62011-12-15 14:55:53 -0800868 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530869 "MCI UNHALT BT GPM <sent>\n");
870 }
871 }
872
873 if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) ==
874 MCI_GPM_COEX_BT_GPM_HALT) {
875
876 mci->halted_bt_gpm = !queue;
877
878 if (queue)
Joe Perchesd2182b62011-12-15 14:55:53 -0800879 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530880 "MCI HALT BT GPM <not sent>\n");
881 else
Joe Perchesd2182b62011-12-15 14:55:53 -0800882 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530883 "MCI UNHALT BT GPM <sent>\n");
884 }
885
886 break;
887 default:
888 break;
889 }
890}
891
892void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
893{
894 struct ath_common *common = ath9k_hw_common(ah);
895 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
896
Felix Fietkau8a309302011-12-17 16:47:56 +0100897 if (!ATH9K_HW_CAP_MCI)
898 return;
899
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530900 if (mci->update_2g5g) {
901 if (mci->is_2g) {
902
903 ar9003_mci_send_2g5g_status(ah, true);
Joe Perchesd2182b62011-12-15 14:55:53 -0800904 ath_dbg(common, MCI, "MCI Send LNA trans\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530905 ar9003_mci_send_lna_transfer(ah, true);
906 udelay(5);
907
908 REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
909 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
910
911 if (AR_SREV_9462_20(ah)) {
912 REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
913 AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
914 if (!(mci->config &
915 ATH_MCI_CONFIG_DISABLE_OSLA)) {
916 REG_SET_BIT(ah, AR_BTCOEX_CTRL,
917 AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
918 }
919 }
920 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -0800921 ath_dbg(common, MCI, "MCI Send LNA take\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530922 ar9003_mci_send_lna_take(ah, true);
923 udelay(5);
924
925 REG_SET_BIT(ah, AR_MCI_TX_CTRL,
926 AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
927
928 if (AR_SREV_9462_20(ah)) {
929 REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
930 AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
931 REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
932 AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
933 }
934
935 ar9003_mci_send_2g5g_status(ah, true);
936 }
937 }
938}
939
940bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag,
941 u32 *payload, u8 len, bool wait_done,
942 bool check_bt)
943{
944 struct ath_common *common = ath9k_hw_common(ah);
945 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
946 bool msg_sent = false;
947 u32 regval;
948 u32 saved_mci_int_en;
949 int i;
950
Felix Fietkau8a309302011-12-17 16:47:56 +0100951 if (!ATH9K_HW_CAP_MCI)
952 return false;
953
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530954 saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN);
955 regval = REG_READ(ah, AR_BTCOEX_CTRL);
956
957 if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) {
958
Joe Perchesd2182b62011-12-15 14:55:53 -0800959 ath_dbg(common, MCI,
960 "MCI Not sending 0x%x. MCI is not enabled. full_sleep = %d\n",
961 header,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530962 (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0);
963
964 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
965 return false;
966
967 } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) {
968
Joe Perchesd2182b62011-12-15 14:55:53 -0800969 ath_dbg(common, MCI,
970 "MCI Don't send message 0x%x. BT is in sleep state\n",
971 header);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +0530972
973 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
974 return false;
975 }
976
977 if (wait_done)
978 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0);
979
980 /* Need to clear SW_MSG_DONE raw bit before wait */
981
982 REG_WRITE(ah, AR_MCI_INTERRUPT_RAW,
983 (AR_MCI_INTERRUPT_SW_MSG_DONE |
984 AR_MCI_INTERRUPT_MSG_FAIL_MASK));
985
986 if (payload) {
987 for (i = 0; (i * 4) < len; i++)
988 REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4),
989 *(payload + i));
990 }
991
992 REG_WRITE(ah, AR_MCI_COMMAND0,
993 (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP),
994 AR_MCI_COMMAND0_DISABLE_TIMESTAMP) |
995 SM(len, AR_MCI_COMMAND0_LEN) |
996 SM(header, AR_MCI_COMMAND0_HEADER)));
997
998 if (wait_done &&
999 !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW,
1000 AR_MCI_INTERRUPT_SW_MSG_DONE, 500)))
1001 ar9003_mci_queue_unsent_gpm(ah, header, payload, true);
1002 else {
1003 ar9003_mci_queue_unsent_gpm(ah, header, payload, false);
1004 msg_sent = true;
1005 }
1006
1007 if (wait_done)
1008 REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en);
1009
1010 return msg_sent;
1011}
1012EXPORT_SYMBOL(ar9003_mci_send_message);
1013
Sujith Manoharanf2f408e2012-02-22 12:41:06 +05301014void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable)
1015{
1016 struct ath_common *common = ath9k_hw_common(ah);
1017 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
1018 u32 pld[4] = {0, 0, 0, 0};
1019
1020 if ((mci_hw->bt_state != MCI_BT_AWAKE) ||
1021 (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))
1022 return;
1023
1024 /* send CAL_REQ only when BT is AWAKE. */
1025 ath_dbg(common, MCI, "MCI send WLAN_CAL_REQ 0x%x\n",
1026 mci_hw->wlan_cal_seq);
1027
1028 MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_REQ);
1029 pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_seq++;
1030
1031 ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
1032
1033 /* Wait BT_CAL_GRANT for 50ms */
1034 ath_dbg(common, MCI, "MCI wait for BT_CAL_GRANT\n");
1035
1036 if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) {
1037 ath_dbg(common, MCI, "MCI got BT_CAL_GRANT\n");
1038 } else {
1039 is_reusable = false;
1040 ath_dbg(common, MCI, "MCI BT is not responding\n");
1041 }
1042}
1043
1044void ar9003_mci_init_cal_done(struct ath_hw *ah)
1045{
1046 struct ath_common *common = ath9k_hw_common(ah);
1047 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
1048 u32 pld[4] = {0, 0, 0, 0};
1049
1050 if ((mci_hw->bt_state != MCI_BT_AWAKE) ||
1051 (mci_hw->config & ATH_MCI_CONFIG_DISABLE_MCI_CAL))
1052 return;
1053
1054 ath_dbg(common, MCI, "MCI Send WLAN_CAL_DONE 0x%x\n",
1055 mci_hw->wlan_cal_done);
1056
1057 MCI_GPM_SET_CAL_TYPE(pld, MCI_GPM_WLAN_CAL_DONE);
1058 pld[MCI_GPM_WLAN_CAL_W_SEQUENCE] = mci_hw->wlan_cal_done++;
1059 ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, true, false);
1060}
1061
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301062void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf,
1063 u16 len, u32 sched_addr)
1064{
1065 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301066
Felix Fietkau8a309302011-12-17 16:47:56 +01001067 if (!ATH9K_HW_CAP_MCI)
1068 return;
1069
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301070 mci->gpm_addr = gpm_addr;
1071 mci->gpm_buf = gpm_buf;
1072 mci->gpm_len = len;
1073 mci->sched_addr = sched_addr;
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301074
1075 ar9003_mci_reset(ah, true, true, true);
1076}
1077EXPORT_SYMBOL(ar9003_mci_setup);
1078
1079void ar9003_mci_cleanup(struct ath_hw *ah)
1080{
Felix Fietkau8a309302011-12-17 16:47:56 +01001081 if (!ATH9K_HW_CAP_MCI)
1082 return;
1083
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301084 /* Turn off MCI and Jupiter mode. */
1085 REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301086 ar9003_mci_disable_interrupt(ah);
1087}
1088EXPORT_SYMBOL(ar9003_mci_cleanup);
1089
1090static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type,
1091 u8 gpm_opcode, u32 *p_gpm)
1092{
1093 struct ath_common *common = ath9k_hw_common(ah);
1094 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
1095 u8 *p_data = (u8 *) p_gpm;
1096
1097 if (gpm_type != MCI_GPM_COEX_AGENT)
1098 return;
1099
1100 switch (gpm_opcode) {
1101 case MCI_GPM_COEX_VERSION_QUERY:
Joe Perchesd2182b62011-12-15 14:55:53 -08001102 ath_dbg(common, MCI, "MCI Recv GPM COEX Version Query\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301103 ar9003_mci_send_coex_version_response(ah, true);
1104 break;
1105 case MCI_GPM_COEX_VERSION_RESPONSE:
Joe Perchesd2182b62011-12-15 14:55:53 -08001106 ath_dbg(common, MCI, "MCI Recv GPM COEX Version Response\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301107 mci->bt_ver_major =
1108 *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION);
1109 mci->bt_ver_minor =
1110 *(p_data + MCI_GPM_COEX_B_MINOR_VERSION);
1111 mci->bt_version_known = true;
Joe Perchesd2182b62011-12-15 14:55:53 -08001112 ath_dbg(common, MCI, "MCI BT Coex version: %d.%d\n",
1113 mci->bt_ver_major, mci->bt_ver_minor);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301114 break;
1115 case MCI_GPM_COEX_STATUS_QUERY:
Joe Perchesd2182b62011-12-15 14:55:53 -08001116 ath_dbg(common, MCI,
1117 "MCI Recv GPM COEX Status Query = 0x%02X\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301118 *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP));
1119 mci->wlan_channels_update = true;
1120 ar9003_mci_send_coex_wlan_channels(ah, true);
1121 break;
1122 case MCI_GPM_COEX_BT_PROFILE_INFO:
1123 mci->query_bt = true;
Joe Perchesd2182b62011-12-15 14:55:53 -08001124 ath_dbg(common, MCI, "MCI Recv GPM COEX BT_Profile_Info\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301125 break;
1126 case MCI_GPM_COEX_BT_STATUS_UPDATE:
1127 mci->query_bt = true;
Joe Perchesd2182b62011-12-15 14:55:53 -08001128 ath_dbg(common, MCI,
1129 "MCI Recv GPM COEX BT_Status_Update SEQ=%d (drop&query)\n",
1130 *(p_gpm + 3));
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301131 break;
1132 default:
1133 break;
1134 }
1135}
1136
1137u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type,
1138 u8 gpm_opcode, int time_out)
1139{
1140 struct ath_common *common = ath9k_hw_common(ah);
1141 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
1142 u32 *p_gpm = NULL, mismatch = 0, more_data;
1143 u32 offset;
1144 u8 recv_type = 0, recv_opcode = 0;
1145 bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE);
1146
Felix Fietkau8a309302011-12-17 16:47:56 +01001147 if (!ATH9K_HW_CAP_MCI)
1148 return 0;
1149
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301150 more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE;
1151
1152 while (time_out > 0) {
1153 if (p_gpm) {
1154 MCI_GPM_RECYCLE(p_gpm);
1155 p_gpm = NULL;
1156 }
1157
1158 if (more_data != MCI_GPM_MORE)
1159 time_out = ar9003_mci_wait_for_interrupt(ah,
1160 AR_MCI_INTERRUPT_RX_MSG_RAW,
1161 AR_MCI_INTERRUPT_RX_MSG_GPM,
1162 time_out);
1163
1164 if (!time_out)
1165 break;
1166
1167 offset = ar9003_mci_state(ah,
1168 MCI_STATE_NEXT_GPM_OFFSET, &more_data);
1169
1170 if (offset == MCI_GPM_INVALID)
1171 continue;
1172
1173 p_gpm = (u32 *) (mci->gpm_buf + offset);
1174 recv_type = MCI_GPM_TYPE(p_gpm);
1175 recv_opcode = MCI_GPM_OPCODE(p_gpm);
1176
1177 if (MCI_GPM_IS_CAL_TYPE(recv_type)) {
1178
1179 if (recv_type == gpm_type) {
1180
1181 if ((gpm_type == MCI_GPM_BT_CAL_DONE) &&
1182 !b_is_bt_cal_done) {
1183 gpm_type = MCI_GPM_BT_CAL_GRANT;
Joe Perchesd2182b62011-12-15 14:55:53 -08001184 ath_dbg(common, MCI,
1185 "MCI Recv BT_CAL_DONE wait BT_CAL_GRANT\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301186 continue;
1187 }
1188
1189 break;
1190 }
1191 } else if ((recv_type == gpm_type) &&
1192 (recv_opcode == gpm_opcode))
1193 break;
1194
1195 /* not expected message */
1196
1197 /*
1198 * check if it's cal_grant
1199 *
1200 * When we're waiting for cal_grant in reset routine,
1201 * it's possible that BT sends out cal_request at the
1202 * same time. Since BT's calibration doesn't happen
1203 * that often, we'll let BT completes calibration then
1204 * we continue to wait for cal_grant from BT.
1205 * Orginal: Wait BT_CAL_GRANT.
1206 * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait
1207 * BT_CAL_DONE -> Wait BT_CAL_GRANT.
1208 */
1209
1210 if ((gpm_type == MCI_GPM_BT_CAL_GRANT) &&
1211 (recv_type == MCI_GPM_BT_CAL_REQ)) {
1212
1213 u32 payload[4] = {0, 0, 0, 0};
1214
1215 gpm_type = MCI_GPM_BT_CAL_DONE;
Joe Perchesd2182b62011-12-15 14:55:53 -08001216 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301217 "MCI Rcv BT_CAL_REQ, send WLAN_CAL_GRANT\n");
1218
1219 MCI_GPM_SET_CAL_TYPE(payload,
1220 MCI_GPM_WLAN_CAL_GRANT);
1221
1222 ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16,
1223 false, false);
1224
Joe Perchesd2182b62011-12-15 14:55:53 -08001225 ath_dbg(common, MCI, "MCI now wait for BT_CAL_DONE\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301226
1227 continue;
1228 } else {
Joe Perchesd2182b62011-12-15 14:55:53 -08001229 ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n",
1230 *(p_gpm + 1));
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301231 mismatch++;
1232 ar9003_mci_process_gpm_extra(ah, recv_type,
1233 recv_opcode, p_gpm);
1234 }
1235 }
1236 if (p_gpm) {
1237 MCI_GPM_RECYCLE(p_gpm);
1238 p_gpm = NULL;
1239 }
1240
1241 if (time_out <= 0) {
1242 time_out = 0;
Joe Perchesd2182b62011-12-15 14:55:53 -08001243 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301244 "MCI GPM received timeout, mismatch = %d\n", mismatch);
1245 } else
Joe Perchesd2182b62011-12-15 14:55:53 -08001246 ath_dbg(common, MCI, "MCI Receive GPM type=0x%x, code=0x%x\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301247 gpm_type, gpm_opcode);
1248
1249 while (more_data == MCI_GPM_MORE) {
1250
Joe Perchesd2182b62011-12-15 14:55:53 -08001251 ath_dbg(common, MCI, "MCI discard remaining GPM\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301252 offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET,
1253 &more_data);
1254
1255 if (offset == MCI_GPM_INVALID)
1256 break;
1257
1258 p_gpm = (u32 *) (mci->gpm_buf + offset);
1259 recv_type = MCI_GPM_TYPE(p_gpm);
1260 recv_opcode = MCI_GPM_OPCODE(p_gpm);
1261
1262 if (!MCI_GPM_IS_CAL_TYPE(recv_type))
1263 ar9003_mci_process_gpm_extra(ah, recv_type,
1264 recv_opcode, p_gpm);
1265
1266 MCI_GPM_RECYCLE(p_gpm);
1267 }
1268
1269 return time_out;
1270}
1271
1272u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
1273{
1274 struct ath_common *common = ath9k_hw_common(ah);
1275 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
1276 u32 value = 0, more_gpm = 0, gpm_ptr;
1277 u8 query_type;
1278
Felix Fietkau8a309302011-12-17 16:47:56 +01001279 if (!ATH9K_HW_CAP_MCI)
1280 return 0;
1281
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301282 switch (state_type) {
1283 case MCI_STATE_ENABLE:
1284 if (mci->ready) {
1285
1286 value = REG_READ(ah, AR_BTCOEX_CTRL);
1287
1288 if ((value == 0xdeadbeef) || (value == 0xffffffff))
1289 value = 0;
1290 }
1291 value &= AR_BTCOEX_CTRL_MCI_MODE_EN;
1292 break;
1293 case MCI_STATE_INIT_GPM_OFFSET:
1294 value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
Joe Perchesd2182b62011-12-15 14:55:53 -08001295 ath_dbg(common, MCI, "MCI GPM initial WRITE_PTR=%d\n", value);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301296 mci->gpm_idx = value;
1297 break;
1298 case MCI_STATE_NEXT_GPM_OFFSET:
1299 case MCI_STATE_LAST_GPM_OFFSET:
1300 /*
1301 * This could be useful to avoid new GPM message interrupt which
1302 * may lead to spurious interrupt after power sleep, or multiple
1303 * entry of ath_mci_intr().
1304 * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can
1305 * alleviate this effect, but clearing GPM RX interrupt bit is
1306 * safe, because whether this is called from hw or driver code
1307 * there must be an interrupt bit set/triggered initially
1308 */
1309 REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
1310 AR_MCI_INTERRUPT_RX_MSG_GPM);
1311
1312 gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
1313 value = gpm_ptr;
1314
1315 if (value == 0)
1316 value = mci->gpm_len - 1;
1317 else if (value >= mci->gpm_len) {
1318 if (value != 0xFFFF) {
1319 value = 0;
Joe Perchesd2182b62011-12-15 14:55:53 -08001320 ath_dbg(common, MCI,
1321 "MCI GPM offset out of range\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301322 }
1323 } else
1324 value--;
1325
1326 if (value == 0xFFFF) {
1327 value = MCI_GPM_INVALID;
1328 more_gpm = MCI_GPM_NOMORE;
Joe Perchesd2182b62011-12-15 14:55:53 -08001329 ath_dbg(common, MCI,
1330 "MCI GPM ptr invalid @ptr=%d, offset=%d, more=GPM_NOMORE\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301331 gpm_ptr, value);
1332 } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) {
1333
1334 if (gpm_ptr == mci->gpm_idx) {
1335 value = MCI_GPM_INVALID;
1336 more_gpm = MCI_GPM_NOMORE;
1337
Joe Perchesd2182b62011-12-15 14:55:53 -08001338 ath_dbg(common, MCI,
1339 "MCI GPM message not available @ptr=%d, @offset=%d, more=GPM_NOMORE\n",
1340 gpm_ptr, value);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301341 } else {
1342 for (;;) {
1343
1344 u32 temp_index;
1345
1346 /* skip reserved GPM if any */
1347
1348 if (value != mci->gpm_idx)
1349 more_gpm = MCI_GPM_MORE;
1350 else
1351 more_gpm = MCI_GPM_NOMORE;
1352
1353 temp_index = mci->gpm_idx;
1354 mci->gpm_idx++;
1355
1356 if (mci->gpm_idx >=
1357 mci->gpm_len)
1358 mci->gpm_idx = 0;
1359
Joe Perchesd2182b62011-12-15 14:55:53 -08001360 ath_dbg(common, MCI,
1361 "MCI GPM message got ptr=%d, @offset=%d, more=%d\n",
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301362 gpm_ptr, temp_index,
1363 (more_gpm == MCI_GPM_MORE));
1364
1365 if (ar9003_mci_is_gpm_valid(ah,
1366 temp_index)) {
1367 value = temp_index;
1368 break;
1369 }
1370
1371 if (more_gpm == MCI_GPM_NOMORE) {
1372 value = MCI_GPM_INVALID;
1373 break;
1374 }
1375 }
1376 }
1377 if (p_data)
1378 *p_data = more_gpm;
1379 }
1380
1381 if (value != MCI_GPM_INVALID)
1382 value <<= 4;
1383
1384 break;
1385 case MCI_STATE_LAST_SCHD_MSG_OFFSET:
1386 value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
1387 AR_MCI_RX_LAST_SCHD_MSG_INDEX);
1388 /* Make it in bytes */
1389 value <<= 4;
1390 break;
1391
1392 case MCI_STATE_REMOTE_SLEEP:
1393 value = MS(REG_READ(ah, AR_MCI_RX_STATUS),
1394 AR_MCI_RX_REMOTE_SLEEP) ?
1395 MCI_BT_SLEEP : MCI_BT_AWAKE;
1396 break;
1397
1398 case MCI_STATE_CONT_RSSI_POWER:
1399 value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER);
1400 break;
1401
1402 case MCI_STATE_CONT_PRIORITY:
1403 value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY);
1404 break;
1405
1406 case MCI_STATE_CONT_TXRX:
1407 value = MS(mci->cont_status, AR_MCI_CONT_TXRX);
1408 break;
1409
1410 case MCI_STATE_BT:
1411 value = mci->bt_state;
1412 break;
1413
1414 case MCI_STATE_SET_BT_SLEEP:
1415 mci->bt_state = MCI_BT_SLEEP;
1416 break;
1417
1418 case MCI_STATE_SET_BT_AWAKE:
1419 mci->bt_state = MCI_BT_AWAKE;
1420 ar9003_mci_send_coex_version_query(ah, true);
1421 ar9003_mci_send_coex_wlan_channels(ah, true);
1422
1423 if (mci->unhalt_bt_gpm) {
1424
Joe Perchesd2182b62011-12-15 14:55:53 -08001425 ath_dbg(common, MCI, "MCI unhalt BT GPM\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301426 ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);
1427 }
1428
1429 ar9003_mci_2g5g_switch(ah, true);
1430 break;
1431
1432 case MCI_STATE_SET_BT_CAL_START:
1433 mci->bt_state = MCI_BT_CAL_START;
1434 break;
1435
1436 case MCI_STATE_SET_BT_CAL:
1437 mci->bt_state = MCI_BT_CAL;
1438 break;
1439
1440 case MCI_STATE_RESET_REQ_WAKE:
1441 ar9003_mci_reset_req_wakeup(ah);
1442 mci->update_2g5g = true;
1443
1444 if ((AR_SREV_9462_20_OR_LATER(ah)) &&
1445 (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK)) {
1446 /* Check if we still have control of the GPIOs */
1447 if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) &
1448 ATH_MCI_CONFIG_MCI_OBS_GPIO) !=
1449 ATH_MCI_CONFIG_MCI_OBS_GPIO) {
1450
Joe Perchesd2182b62011-12-15 14:55:53 -08001451 ath_dbg(common, MCI,
1452 "MCI reconfigure observation\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301453 ar9003_mci_observation_set_up(ah);
1454 }
1455 }
1456 break;
1457
1458 case MCI_STATE_SEND_WLAN_COEX_VERSION:
1459 ar9003_mci_send_coex_version_response(ah, true);
1460 break;
1461
1462 case MCI_STATE_SET_BT_COEX_VERSION:
1463
1464 if (!p_data)
Joe Perchesd2182b62011-12-15 14:55:53 -08001465 ath_dbg(common, MCI,
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301466 "MCI Set BT Coex version with NULL data!!\n");
1467 else {
1468 mci->bt_ver_major = (*p_data >> 8) & 0xff;
1469 mci->bt_ver_minor = (*p_data) & 0xff;
1470 mci->bt_version_known = true;
Joe Perchesd2182b62011-12-15 14:55:53 -08001471 ath_dbg(common, MCI, "MCI BT version set: %d.%d\n",
1472 mci->bt_ver_major, mci->bt_ver_minor);
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301473 }
1474 break;
1475
1476 case MCI_STATE_SEND_WLAN_CHANNELS:
1477 if (p_data) {
1478 if (((mci->wlan_channels[1] & 0xffff0000) ==
1479 (*(p_data + 1) & 0xffff0000)) &&
1480 (mci->wlan_channels[2] == *(p_data + 2)) &&
1481 (mci->wlan_channels[3] == *(p_data + 3)))
1482 break;
1483
1484 mci->wlan_channels[0] = *p_data++;
1485 mci->wlan_channels[1] = *p_data++;
1486 mci->wlan_channels[2] = *p_data++;
1487 mci->wlan_channels[3] = *p_data++;
1488 }
1489 mci->wlan_channels_update = true;
1490 ar9003_mci_send_coex_wlan_channels(ah, true);
1491 break;
1492
1493 case MCI_STATE_SEND_VERSION_QUERY:
1494 ar9003_mci_send_coex_version_query(ah, true);
1495 break;
1496
1497 case MCI_STATE_SEND_STATUS_QUERY:
Sujith Manoharanc91ec462012-02-22 12:40:03 +05301498 query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY;
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301499
1500 ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
1501 break;
1502
1503 case MCI_STATE_NEED_FLUSH_BT_INFO:
1504 /*
1505 * btcoex_hw.mci.unhalt_bt_gpm means whether it's
1506 * needed to send UNHALT message. It's set whenever
1507 * there's a request to send HALT message.
1508 * mci_halted_bt_gpm means whether HALT message is sent
1509 * out successfully.
1510 *
1511 * Checking (mci_unhalt_bt_gpm == false) instead of
1512 * checking (ah->mci_halted_bt_gpm == false) will make
1513 * sure currently is in UNHALT-ed mode and BT can
1514 * respond to status query.
1515 */
1516 value = (!mci->unhalt_bt_gpm &&
1517 mci->need_flush_btinfo) ? 1 : 0;
1518 if (p_data)
1519 mci->need_flush_btinfo =
1520 (*p_data != 0) ? true : false;
1521 break;
1522
1523 case MCI_STATE_RECOVER_RX:
1524
Joe Perchesd2182b62011-12-15 14:55:53 -08001525 ath_dbg(common, MCI, "MCI hw RECOVER_RX\n");
Mohammed Shafi Shajakhanbbefb872011-11-30 10:41:17 +05301526 ar9003_mci_prep_interface(ah);
1527 mci->query_bt = true;
1528 mci->need_flush_btinfo = true;
1529 ar9003_mci_send_coex_wlan_channels(ah, true);
1530 ar9003_mci_2g5g_switch(ah, true);
1531 break;
1532
1533 case MCI_STATE_NEED_FTP_STOMP:
1534 value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
1535 break;
1536
1537 case MCI_STATE_NEED_TUNING:
1538 value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING);
1539 break;
1540
1541 default:
1542 break;
1543
1544 }
1545
1546 return value;
1547}
1548EXPORT_SYMBOL(ar9003_mci_state);