diff options
author | Mohammed Shafi Shajakhan <mohammed@qca.qualcomm.com> | 2011-11-30 00:11:17 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-30 15:08:43 -0500 |
commit | bbefb8715298ce8c6a1da03da16efaa6f1ff4237 (patch) | |
tree | 73f048140c84fc293a6acc064fd1249ccbe3a3f2 /drivers/net/wireless/ath | |
parent | 16659f6ad86b0e73ef0409a87b74170fbaeda344 (diff) |
ath9k_hw: Add MCI h/w code and state machine
Cc: Wilson Tsao <wtsao@qca.qualcomm.com>
Cc: Senthil Balasubramanian <senthilb@qca.qualcomm.com>
Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_mci.c | 1464 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 26 |
3 files changed, 1492 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 49d3f25f509d..390797db5273 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile | |||
@@ -34,7 +34,8 @@ ath9k_hw-y:= \ | |||
34 | ar9002_mac.o \ | 34 | ar9002_mac.o \ |
35 | ar9003_mac.o \ | 35 | ar9003_mac.o \ |
36 | ar9003_eeprom.o \ | 36 | ar9003_eeprom.o \ |
37 | ar9003_paprd.o | 37 | ar9003_paprd.o \ |
38 | ar9003_mci.o | ||
38 | 39 | ||
39 | obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o | 40 | obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o |
40 | 41 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c new file mode 100644 index 000000000000..8599822dc83f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c | |||
@@ -0,0 +1,1464 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2011 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <linux/export.h> | ||
18 | #include "hw.h" | ||
19 | #include "ar9003_phy.h" | ||
20 | #include "ar9003_mci.h" | ||
21 | |||
22 | static 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 | |||
34 | static 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) { | ||
71 | ath_dbg(common, ATH_DBG_MCI, | ||
72 | "MCI Wait for Reg 0x%08x = 0x%08x timeout.\n", | ||
73 | address, bit_position); | ||
74 | ath_dbg(common, ATH_DBG_MCI, | ||
75 | "MCI INT_RAW = 0x%08x, RX_MSG_RAW = 0x%08x", | ||
76 | 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 | |||
84 | void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done) | ||
85 | { | ||
86 | u32 payload[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00}; | ||
87 | |||
88 | ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0, payload, 16, | ||
89 | wait_done, false); | ||
90 | udelay(5); | ||
91 | } | ||
92 | |||
93 | void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done) | ||
94 | { | ||
95 | u32 payload = 0x00000000; | ||
96 | |||
97 | ar9003_mci_send_message(ah, MCI_LNA_TRANS, 0, &payload, 1, | ||
98 | wait_done, false); | ||
99 | } | ||
100 | |||
101 | static void ar9003_mci_send_req_wake(struct ath_hw *ah, bool wait_done) | ||
102 | { | ||
103 | ar9003_mci_send_message(ah, MCI_REQ_WAKE, MCI_FLAG_DISABLE_TIMESTAMP, | ||
104 | NULL, 0, wait_done, false); | ||
105 | udelay(5); | ||
106 | } | ||
107 | |||
108 | void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done) | ||
109 | { | ||
110 | ar9003_mci_send_message(ah, MCI_SYS_WAKING, MCI_FLAG_DISABLE_TIMESTAMP, | ||
111 | NULL, 0, wait_done, false); | ||
112 | } | ||
113 | |||
114 | static void ar9003_mci_send_lna_take(struct ath_hw *ah, bool wait_done) | ||
115 | { | ||
116 | u32 payload = 0x70000000; | ||
117 | |||
118 | ar9003_mci_send_message(ah, MCI_LNA_TAKE, 0, &payload, 1, | ||
119 | wait_done, false); | ||
120 | } | ||
121 | |||
122 | static void ar9003_mci_send_sys_sleeping(struct ath_hw *ah, bool wait_done) | ||
123 | { | ||
124 | ar9003_mci_send_message(ah, MCI_SYS_SLEEPING, | ||
125 | MCI_FLAG_DISABLE_TIMESTAMP, | ||
126 | NULL, 0, wait_done, false); | ||
127 | } | ||
128 | |||
129 | static void ar9003_mci_send_coex_version_query(struct ath_hw *ah, | ||
130 | bool wait_done) | ||
131 | { | ||
132 | struct ath_common *common = ath9k_hw_common(ah); | ||
133 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
134 | u32 payload[4] = {0, 0, 0, 0}; | ||
135 | |||
136 | if (!mci->bt_version_known && | ||
137 | (mci->bt_state != MCI_BT_SLEEP)) { | ||
138 | ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex version query\n"); | ||
139 | MCI_GPM_SET_TYPE_OPCODE(payload, | ||
140 | MCI_GPM_COEX_AGENT, MCI_GPM_COEX_VERSION_QUERY); | ||
141 | ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, | ||
142 | wait_done, true); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | static void ar9003_mci_send_coex_version_response(struct ath_hw *ah, | ||
147 | bool wait_done) | ||
148 | { | ||
149 | struct ath_common *common = ath9k_hw_common(ah); | ||
150 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
151 | u32 payload[4] = {0, 0, 0, 0}; | ||
152 | |||
153 | ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex version response\n"); | ||
154 | MCI_GPM_SET_TYPE_OPCODE(payload, MCI_GPM_COEX_AGENT, | ||
155 | MCI_GPM_COEX_VERSION_RESPONSE); | ||
156 | *(((u8 *)payload) + MCI_GPM_COEX_B_MAJOR_VERSION) = | ||
157 | mci->wlan_ver_major; | ||
158 | *(((u8 *)payload) + MCI_GPM_COEX_B_MINOR_VERSION) = | ||
159 | mci->wlan_ver_minor; | ||
160 | ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); | ||
161 | } | ||
162 | |||
163 | static void ar9003_mci_send_coex_wlan_channels(struct ath_hw *ah, | ||
164 | bool wait_done) | ||
165 | { | ||
166 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
167 | u32 *payload = &mci->wlan_channels[0]; | ||
168 | |||
169 | if ((mci->wlan_channels_update == true) && | ||
170 | (mci->bt_state != MCI_BT_SLEEP)) { | ||
171 | MCI_GPM_SET_TYPE_OPCODE(payload, | ||
172 | MCI_GPM_COEX_AGENT, MCI_GPM_COEX_WLAN_CHANNELS); | ||
173 | ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, | ||
174 | wait_done, true); | ||
175 | MCI_GPM_SET_TYPE_OPCODE(payload, 0xff, 0xff); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static void ar9003_mci_send_coex_bt_status_query(struct ath_hw *ah, | ||
180 | bool wait_done, u8 query_type) | ||
181 | { | ||
182 | struct ath_common *common = ath9k_hw_common(ah); | ||
183 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
184 | u32 payload[4] = {0, 0, 0, 0}; | ||
185 | bool query_btinfo = !!(query_type & (MCI_GPM_COEX_QUERY_BT_ALL_INFO | | ||
186 | MCI_GPM_COEX_QUERY_BT_TOPOLOGY)); | ||
187 | |||
188 | if (mci->bt_state != MCI_BT_SLEEP) { | ||
189 | |||
190 | ath_dbg(common, ATH_DBG_MCI, | ||
191 | "MCI Send Coex BT Status Query 0x%02X\n", query_type); | ||
192 | |||
193 | MCI_GPM_SET_TYPE_OPCODE(payload, | ||
194 | MCI_GPM_COEX_AGENT, MCI_GPM_COEX_STATUS_QUERY); | ||
195 | |||
196 | *(((u8 *)payload) + MCI_GPM_COEX_B_BT_BITMAP) = query_type; | ||
197 | /* | ||
198 | * If bt_status_query message is not sent successfully, | ||
199 | * then need_flush_btinfo should be set again. | ||
200 | */ | ||
201 | if (!ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, | ||
202 | wait_done, true)) { | ||
203 | if (query_btinfo) { | ||
204 | mci->need_flush_btinfo = true; | ||
205 | |||
206 | ath_dbg(common, ATH_DBG_MCI, | ||
207 | "MCI send bt_status_query fail, " | ||
208 | "set flush flag again\n"); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | if (query_btinfo) | ||
213 | mci->query_bt = false; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, | ||
218 | bool wait_done) | ||
219 | { | ||
220 | struct ath_common *common = ath9k_hw_common(ah); | ||
221 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
222 | u32 payload[4] = {0, 0, 0, 0}; | ||
223 | |||
224 | ath_dbg(common, ATH_DBG_MCI, "MCI Send Coex %s BT GPM.\n", | ||
225 | (halt) ? "halt" : "unhalt"); | ||
226 | |||
227 | MCI_GPM_SET_TYPE_OPCODE(payload, | ||
228 | MCI_GPM_COEX_AGENT, MCI_GPM_COEX_HALT_BT_GPM); | ||
229 | |||
230 | if (halt) { | ||
231 | mci->query_bt = true; | ||
232 | /* Send next unhalt no matter halt sent or not */ | ||
233 | mci->unhalt_bt_gpm = true; | ||
234 | mci->need_flush_btinfo = true; | ||
235 | *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = | ||
236 | MCI_GPM_COEX_BT_GPM_HALT; | ||
237 | } else | ||
238 | *(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) = | ||
239 | MCI_GPM_COEX_BT_GPM_UNHALT; | ||
240 | |||
241 | ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, wait_done, true); | ||
242 | } | ||
243 | |||
244 | |||
245 | static void ar9003_mci_prep_interface(struct ath_hw *ah) | ||
246 | { | ||
247 | struct ath_common *common = ath9k_hw_common(ah); | ||
248 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
249 | u32 saved_mci_int_en; | ||
250 | u32 mci_timeout = 150; | ||
251 | |||
252 | mci->bt_state = MCI_BT_SLEEP; | ||
253 | saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); | ||
254 | |||
255 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); | ||
256 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, | ||
257 | REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW)); | ||
258 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, | ||
259 | REG_READ(ah, AR_MCI_INTERRUPT_RAW)); | ||
260 | |||
261 | /* Remote Reset */ | ||
262 | ath_dbg(common, ATH_DBG_MCI, "MCI Reset sequence start\n"); | ||
263 | ath_dbg(common, ATH_DBG_MCI, "MCI send REMOTE_RESET\n"); | ||
264 | ar9003_mci_remote_reset(ah, true); | ||
265 | |||
266 | /* | ||
267 | * This delay is required for the reset delay worst case value 255 in | ||
268 | * MCI_COMMAND2 register | ||
269 | */ | ||
270 | |||
271 | if (AR_SREV_9462_10(ah)) | ||
272 | udelay(252); | ||
273 | |||
274 | ath_dbg(common, ATH_DBG_MCI, "MCI Send REQ_WAKE to remoter(BT)\n"); | ||
275 | ar9003_mci_send_req_wake(ah, true); | ||
276 | |||
277 | if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, | ||
278 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING, 500)) { | ||
279 | |||
280 | ath_dbg(common, ATH_DBG_MCI, | ||
281 | "MCI SYS_WAKING from remote(BT)\n"); | ||
282 | mci->bt_state = MCI_BT_AWAKE; | ||
283 | |||
284 | if (AR_SREV_9462_10(ah)) | ||
285 | udelay(10); | ||
286 | /* | ||
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 | |||
305 | ath_dbg(common, ATH_DBG_MCI, | ||
306 | "MCI send SW SYS_WAKING to remote BT\n"); | ||
307 | |||
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 | |||
333 | if (AR_SREV_9462_10(ah) || mci->is_2g) { | ||
334 | /* Send LNA_TRANS */ | ||
335 | ath_dbg(common, ATH_DBG_MCI, | ||
336 | "MCI send LNA_TRANS to BT\n"); | ||
337 | ar9003_mci_send_lna_transfer(ah, true); | ||
338 | udelay(5); | ||
339 | } | ||
340 | |||
341 | if (AR_SREV_9462_10(ah) || (mci->is_2g && | ||
342 | !mci->update_2g5g)) { | ||
343 | if (ar9003_mci_wait_for_interrupt(ah, | ||
344 | AR_MCI_INTERRUPT_RX_MSG_RAW, | ||
345 | AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, | ||
346 | mci_timeout)) | ||
347 | ath_dbg(common, ATH_DBG_MCI, | ||
348 | "MCI WLAN has control over the LNA & " | ||
349 | "BT obeys it\n"); | ||
350 | else | ||
351 | ath_dbg(common, ATH_DBG_MCI, | ||
352 | "MCI BT didn't respond to" | ||
353 | "LNA_TRANS\n"); | ||
354 | } | ||
355 | |||
356 | if (AR_SREV_9462_10(ah)) { | ||
357 | /* Send another remote_reset to deassert BT clk_req. */ | ||
358 | ath_dbg(common, ATH_DBG_MCI, | ||
359 | "MCI another remote_reset to " | ||
360 | "deassert clk_req\n"); | ||
361 | ar9003_mci_remote_reset(ah, true); | ||
362 | udelay(252); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | /* Clear the extra redundant SYS_WAKING from BT */ | ||
367 | if ((mci->bt_state == MCI_BT_AWAKE) && | ||
368 | (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, | ||
369 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING)) && | ||
370 | (REG_READ_FIELD(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, | ||
371 | AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) == 0)) { | ||
372 | |||
373 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, | ||
374 | AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING); | ||
375 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, | ||
376 | AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE); | ||
377 | } | ||
378 | |||
379 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); | ||
380 | } | ||
381 | |||
382 | void ar9003_mci_disable_interrupt(struct ath_hw *ah) | ||
383 | { | ||
384 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); | ||
385 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0); | ||
386 | } | ||
387 | |||
388 | void ar9003_mci_enable_interrupt(struct ath_hw *ah) | ||
389 | { | ||
390 | |||
391 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, AR_MCI_INTERRUPT_DEFAULT); | ||
392 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, | ||
393 | AR_MCI_INTERRUPT_RX_MSG_DEFAULT); | ||
394 | } | ||
395 | |||
396 | bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints) | ||
397 | { | ||
398 | u32 intr; | ||
399 | |||
400 | intr = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_RAW); | ||
401 | return ((intr & ints) == ints); | ||
402 | } | ||
403 | |||
404 | void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, | ||
405 | u32 *rx_msg_intr) | ||
406 | { | ||
407 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
408 | *raw_intr = mci->raw_intr; | ||
409 | *rx_msg_intr = mci->rx_msg_intr; | ||
410 | |||
411 | /* Clean int bits after the values are read. */ | ||
412 | mci->raw_intr = 0; | ||
413 | mci->rx_msg_intr = 0; | ||
414 | } | ||
415 | EXPORT_SYMBOL(ar9003_mci_get_interrupt); | ||
416 | |||
417 | void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g) | ||
418 | { | ||
419 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
420 | |||
421 | if (!mci->update_2g5g && | ||
422 | (mci->is_2g != is_2g)) | ||
423 | mci->update_2g5g = true; | ||
424 | |||
425 | mci->is_2g = is_2g; | ||
426 | } | ||
427 | |||
428 | static bool ar9003_mci_is_gpm_valid(struct ath_hw *ah, u32 msg_index) | ||
429 | { | ||
430 | struct ath_common *common = ath9k_hw_common(ah); | ||
431 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
432 | u32 *payload; | ||
433 | u32 recv_type, offset; | ||
434 | |||
435 | if (msg_index == MCI_GPM_INVALID) | ||
436 | return false; | ||
437 | |||
438 | offset = msg_index << 4; | ||
439 | |||
440 | payload = (u32 *)(mci->gpm_buf + offset); | ||
441 | recv_type = MCI_GPM_TYPE(payload); | ||
442 | |||
443 | if (recv_type == MCI_GPM_RSVD_PATTERN) { | ||
444 | ath_dbg(common, ATH_DBG_MCI, "MCI Skip RSVD GPM\n"); | ||
445 | return false; | ||
446 | } | ||
447 | |||
448 | return true; | ||
449 | } | ||
450 | |||
451 | static void ar9003_mci_observation_set_up(struct ath_hw *ah) | ||
452 | { | ||
453 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
454 | if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) { | ||
455 | |||
456 | ath9k_hw_cfg_output(ah, 3, | ||
457 | AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); | ||
458 | ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK); | ||
459 | ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); | ||
460 | ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); | ||
461 | |||
462 | } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) { | ||
463 | |||
464 | ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX); | ||
465 | ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX); | ||
466 | ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); | ||
467 | ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); | ||
468 | ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
469 | |||
470 | } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) { | ||
471 | |||
472 | ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); | ||
473 | ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); | ||
474 | ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); | ||
475 | ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); | ||
476 | |||
477 | } else | ||
478 | return; | ||
479 | |||
480 | REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); | ||
481 | |||
482 | if (AR_SREV_9462_20_OR_LATER(ah)) { | ||
483 | REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, | ||
484 | AR_GLB_DS_JTAG_DISABLE, 1); | ||
485 | REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, | ||
486 | AR_GLB_WLAN_UART_INTF_EN, 0); | ||
487 | REG_SET_BIT(ah, AR_GLB_GPIO_CONTROL, | ||
488 | ATH_MCI_CONFIG_MCI_OBS_GPIO); | ||
489 | } | ||
490 | |||
491 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0); | ||
492 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1); | ||
493 | REG_WRITE(ah, AR_OBS, 0x4b); | ||
494 | REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03); | ||
495 | REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01); | ||
496 | REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02); | ||
497 | REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03); | ||
498 | REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, | ||
499 | AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07); | ||
500 | } | ||
501 | |||
502 | static bool ar9003_mci_send_coex_bt_flags(struct ath_hw *ah, bool wait_done, | ||
503 | u8 opcode, u32 bt_flags) | ||
504 | { | ||
505 | struct ath_common *common = ath9k_hw_common(ah); | ||
506 | u32 pld[4] = {0, 0, 0, 0}; | ||
507 | |||
508 | MCI_GPM_SET_TYPE_OPCODE(pld, | ||
509 | MCI_GPM_COEX_AGENT, MCI_GPM_COEX_BT_UPDATE_FLAGS); | ||
510 | |||
511 | *(((u8 *)pld) + MCI_GPM_COEX_B_BT_FLAGS_OP) = opcode; | ||
512 | *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 0) = bt_flags & 0xFF; | ||
513 | *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 1) = (bt_flags >> 8) & 0xFF; | ||
514 | *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 2) = (bt_flags >> 16) & 0xFF; | ||
515 | *(((u8 *)pld) + MCI_GPM_COEX_W_BT_FLAGS + 3) = (bt_flags >> 24) & 0xFF; | ||
516 | |||
517 | ath_dbg(common, ATH_DBG_MCI, | ||
518 | "MCI BT_MCI_FLAGS: Send Coex BT Update Flags %s 0x%08x\n", | ||
519 | (opcode == MCI_GPM_COEX_BT_FLAGS_READ) ? "READ" : | ||
520 | ((opcode == MCI_GPM_COEX_BT_FLAGS_SET) ? "SET" : "CLEAR"), | ||
521 | bt_flags); | ||
522 | |||
523 | return ar9003_mci_send_message(ah, MCI_GPM, 0, pld, 16, | ||
524 | wait_done, true); | ||
525 | } | ||
526 | |||
527 | void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, | ||
528 | bool is_full_sleep) | ||
529 | { | ||
530 | struct ath_common *common = ath9k_hw_common(ah); | ||
531 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
532 | u32 regval, thresh; | ||
533 | |||
534 | ath_dbg(common, ATH_DBG_MCI, "MCI full_sleep = %d, is_2g = %d\n", | ||
535 | is_full_sleep, is_2g); | ||
536 | |||
537 | /* | ||
538 | * GPM buffer and scheduling message buffer are not allocated | ||
539 | */ | ||
540 | |||
541 | if (!mci->gpm_addr && !mci->sched_addr) { | ||
542 | ath_dbg(common, ATH_DBG_MCI, | ||
543 | "MCI GPM and schedule buffers are not allocated"); | ||
544 | return; | ||
545 | } | ||
546 | |||
547 | if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { | ||
548 | ath_dbg(common, ATH_DBG_MCI, | ||
549 | "MCI it's deadbeef, quit mci_reset\n"); | ||
550 | return; | ||
551 | } | ||
552 | |||
553 | /* Program MCI DMA related registers */ | ||
554 | REG_WRITE(ah, AR_MCI_GPM_0, mci->gpm_addr); | ||
555 | REG_WRITE(ah, AR_MCI_GPM_1, mci->gpm_len); | ||
556 | REG_WRITE(ah, AR_MCI_SCHD_TABLE_0, mci->sched_addr); | ||
557 | |||
558 | /* | ||
559 | * To avoid MCI state machine be affected by incoming remote MCI msgs, | ||
560 | * MCI mode will be enabled later, right before reset the MCI TX and RX. | ||
561 | */ | ||
562 | |||
563 | regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | | ||
564 | SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | | ||
565 | SM(1, AR_BTCOEX_CTRL_PA_SHARED) | | ||
566 | SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | | ||
567 | SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | | ||
568 | SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | | ||
569 | SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | | ||
570 | SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | | ||
571 | SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); | ||
572 | |||
573 | if (is_2g && (AR_SREV_9462_20(ah)) && | ||
574 | !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) { | ||
575 | |||
576 | regval |= SM(1, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); | ||
577 | ath_dbg(common, ATH_DBG_MCI, | ||
578 | "MCI sched one step look ahead\n"); | ||
579 | |||
580 | if (!(mci->config & | ||
581 | ATH_MCI_CONFIG_DISABLE_AGGR_THRESH)) { | ||
582 | |||
583 | thresh = MS(mci->config, | ||
584 | ATH_MCI_CONFIG_AGGR_THRESH); | ||
585 | thresh &= 7; | ||
586 | regval |= SM(1, | ||
587 | AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN); | ||
588 | regval |= SM(thresh, AR_BTCOEX_CTRL_AGGR_THRESH); | ||
589 | |||
590 | REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, | ||
591 | AR_MCI_SCHD_TABLE_2_HW_BASED, 1); | ||
592 | REG_RMW_FIELD(ah, AR_MCI_SCHD_TABLE_2, | ||
593 | AR_MCI_SCHD_TABLE_2_MEM_BASED, 1); | ||
594 | |||
595 | } else | ||
596 | ath_dbg(common, ATH_DBG_MCI, | ||
597 | "MCI sched aggr thresh: off\n"); | ||
598 | } else | ||
599 | ath_dbg(common, ATH_DBG_MCI, | ||
600 | "MCI SCHED one step look ahead off\n"); | ||
601 | |||
602 | if (AR_SREV_9462_10(ah)) | ||
603 | regval |= SM(1, AR_BTCOEX_CTRL_SPDT_ENABLE_10); | ||
604 | |||
605 | REG_WRITE(ah, AR_BTCOEX_CTRL, regval); | ||
606 | |||
607 | if (AR_SREV_9462_20(ah)) { | ||
608 | REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, | ||
609 | AR_BTCOEX_CTRL_SPDT_ENABLE); | ||
610 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL3, | ||
611 | AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT, 20); | ||
612 | } | ||
613 | |||
614 | REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_RX_DEWEIGHT, 1); | ||
615 | REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); | ||
616 | |||
617 | thresh = MS(mci->config, ATH_MCI_CONFIG_CLK_DIV); | ||
618 | REG_RMW_FIELD(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_CLK_DIV, thresh); | ||
619 | REG_SET_BIT(ah, AR_BTCOEX_CTRL, AR_BTCOEX_CTRL_MCI_MODE_EN); | ||
620 | |||
621 | /* Resetting the Rx and Tx paths of MCI */ | ||
622 | regval = REG_READ(ah, AR_MCI_COMMAND2); | ||
623 | regval |= SM(1, AR_MCI_COMMAND2_RESET_TX); | ||
624 | REG_WRITE(ah, AR_MCI_COMMAND2, regval); | ||
625 | |||
626 | udelay(1); | ||
627 | |||
628 | regval &= ~SM(1, AR_MCI_COMMAND2_RESET_TX); | ||
629 | REG_WRITE(ah, AR_MCI_COMMAND2, regval); | ||
630 | |||
631 | if (is_full_sleep) { | ||
632 | ar9003_mci_mute_bt(ah); | ||
633 | udelay(100); | ||
634 | } | ||
635 | |||
636 | regval |= SM(1, AR_MCI_COMMAND2_RESET_RX); | ||
637 | REG_WRITE(ah, AR_MCI_COMMAND2, regval); | ||
638 | udelay(1); | ||
639 | regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); | ||
640 | REG_WRITE(ah, AR_MCI_COMMAND2, regval); | ||
641 | |||
642 | ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL); | ||
643 | REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, | ||
644 | (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | | ||
645 | SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); | ||
646 | |||
647 | REG_CLR_BIT(ah, AR_MCI_TX_CTRL, | ||
648 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); | ||
649 | |||
650 | if (AR_SREV_9462_20_OR_LATER(ah)) | ||
651 | ar9003_mci_observation_set_up(ah); | ||
652 | |||
653 | mci->ready = true; | ||
654 | ar9003_mci_prep_interface(ah); | ||
655 | |||
656 | if (en_int) | ||
657 | ar9003_mci_enable_interrupt(ah); | ||
658 | } | ||
659 | |||
660 | void ar9003_mci_mute_bt(struct ath_hw *ah) | ||
661 | { | ||
662 | struct ath_common *common = ath9k_hw_common(ah); | ||
663 | |||
664 | /* disable all MCI messages */ | ||
665 | REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); | ||
666 | REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); | ||
667 | REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); | ||
668 | REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); | ||
669 | REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); | ||
670 | REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); | ||
671 | |||
672 | /* wait pending HW messages to flush out */ | ||
673 | udelay(10); | ||
674 | |||
675 | /* | ||
676 | * Send LNA_TAKE and SYS_SLEEPING when | ||
677 | * 1. reset not after resuming from full sleep | ||
678 | * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment | ||
679 | */ | ||
680 | |||
681 | ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA take\n"); | ||
682 | ar9003_mci_send_lna_take(ah, true); | ||
683 | |||
684 | udelay(5); | ||
685 | |||
686 | ath_dbg(common, ATH_DBG_MCI, "MCI Send sys sleeping\n"); | ||
687 | ar9003_mci_send_sys_sleeping(ah, true); | ||
688 | } | ||
689 | |||
690 | void ar9003_mci_sync_bt_state(struct ath_hw *ah) | ||
691 | { | ||
692 | struct ath_common *common = ath9k_hw_common(ah); | ||
693 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
694 | u32 cur_bt_state; | ||
695 | |||
696 | cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL); | ||
697 | |||
698 | if (mci->bt_state != cur_bt_state) { | ||
699 | ath_dbg(common, ATH_DBG_MCI, | ||
700 | "MCI BT state mismatches. old: %d, new: %d\n", | ||
701 | mci->bt_state, cur_bt_state); | ||
702 | mci->bt_state = cur_bt_state; | ||
703 | } | ||
704 | |||
705 | if (mci->bt_state != MCI_BT_SLEEP) { | ||
706 | |||
707 | ar9003_mci_send_coex_version_query(ah, true); | ||
708 | ar9003_mci_send_coex_wlan_channels(ah, true); | ||
709 | |||
710 | if (mci->unhalt_bt_gpm == true) { | ||
711 | ath_dbg(common, ATH_DBG_MCI, "MCI unhalt BT GPM"); | ||
712 | ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); | ||
713 | } | ||
714 | } | ||
715 | } | ||
716 | |||
717 | static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done) | ||
718 | { | ||
719 | struct ath_common *common = ath9k_hw_common(ah); | ||
720 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
721 | u32 new_flags, to_set, to_clear; | ||
722 | |||
723 | if (AR_SREV_9462_20(ah) && | ||
724 | mci->update_2g5g && | ||
725 | (mci->bt_state != MCI_BT_SLEEP)) { | ||
726 | |||
727 | if (mci->is_2g) { | ||
728 | new_flags = MCI_2G_FLAGS; | ||
729 | to_clear = MCI_2G_FLAGS_CLEAR_MASK; | ||
730 | to_set = MCI_2G_FLAGS_SET_MASK; | ||
731 | } else { | ||
732 | new_flags = MCI_5G_FLAGS; | ||
733 | to_clear = MCI_5G_FLAGS_CLEAR_MASK; | ||
734 | to_set = MCI_5G_FLAGS_SET_MASK; | ||
735 | } | ||
736 | |||
737 | ath_dbg(common, ATH_DBG_MCI, | ||
738 | "MCI BT_MCI_FLAGS: %s 0x%08x clr=0x%08x, set=0x%08x\n", | ||
739 | mci->is_2g ? "2G" : "5G", new_flags, to_clear, to_set); | ||
740 | |||
741 | if (to_clear) | ||
742 | ar9003_mci_send_coex_bt_flags(ah, wait_done, | ||
743 | MCI_GPM_COEX_BT_FLAGS_CLEAR, to_clear); | ||
744 | |||
745 | if (to_set) | ||
746 | ar9003_mci_send_coex_bt_flags(ah, wait_done, | ||
747 | MCI_GPM_COEX_BT_FLAGS_SET, to_set); | ||
748 | } | ||
749 | |||
750 | if (AR_SREV_9462_10(ah) && (mci->bt_state != MCI_BT_SLEEP)) | ||
751 | mci->update_2g5g = false; | ||
752 | } | ||
753 | |||
754 | static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, | ||
755 | u32 *payload, bool queue) | ||
756 | { | ||
757 | struct ath_common *common = ath9k_hw_common(ah); | ||
758 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
759 | u8 type, opcode; | ||
760 | |||
761 | if (queue) { | ||
762 | |||
763 | if (payload) | ||
764 | ath_dbg(common, ATH_DBG_MCI, | ||
765 | "MCI ERROR: Send fail: %02x: %02x %02x %02x\n", | ||
766 | header, | ||
767 | *(((u8 *)payload) + 4), | ||
768 | *(((u8 *)payload) + 5), | ||
769 | *(((u8 *)payload) + 6)); | ||
770 | else | ||
771 | ath_dbg(common, ATH_DBG_MCI, | ||
772 | "MCI ERROR: Send fail: %02x\n", header); | ||
773 | } | ||
774 | |||
775 | /* check if the message is to be queued */ | ||
776 | if (header != MCI_GPM) | ||
777 | return; | ||
778 | |||
779 | type = MCI_GPM_TYPE(payload); | ||
780 | opcode = MCI_GPM_OPCODE(payload); | ||
781 | |||
782 | if (type != MCI_GPM_COEX_AGENT) | ||
783 | return; | ||
784 | |||
785 | switch (opcode) { | ||
786 | case MCI_GPM_COEX_BT_UPDATE_FLAGS: | ||
787 | |||
788 | if (AR_SREV_9462_10(ah)) | ||
789 | break; | ||
790 | |||
791 | if (*(((u8 *)payload) + MCI_GPM_COEX_B_BT_FLAGS_OP) == | ||
792 | MCI_GPM_COEX_BT_FLAGS_READ) | ||
793 | break; | ||
794 | |||
795 | mci->update_2g5g = queue; | ||
796 | |||
797 | if (queue) | ||
798 | ath_dbg(common, ATH_DBG_MCI, | ||
799 | "MCI BT_MCI_FLAGS: 2G5G status <queued> %s.\n", | ||
800 | mci->is_2g ? "2G" : "5G"); | ||
801 | else | ||
802 | ath_dbg(common, ATH_DBG_MCI, | ||
803 | "MCI BT_MCI_FLAGS: 2G5G status <sent> %s.\n", | ||
804 | mci->is_2g ? "2G" : "5G"); | ||
805 | |||
806 | break; | ||
807 | |||
808 | case MCI_GPM_COEX_WLAN_CHANNELS: | ||
809 | |||
810 | mci->wlan_channels_update = queue; | ||
811 | if (queue) | ||
812 | ath_dbg(common, ATH_DBG_MCI, | ||
813 | "MCI WLAN channel map <queued>\n"); | ||
814 | else | ||
815 | ath_dbg(common, ATH_DBG_MCI, | ||
816 | "MCI WLAN channel map <sent>\n"); | ||
817 | break; | ||
818 | |||
819 | case MCI_GPM_COEX_HALT_BT_GPM: | ||
820 | |||
821 | if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == | ||
822 | MCI_GPM_COEX_BT_GPM_UNHALT) { | ||
823 | |||
824 | mci->unhalt_bt_gpm = queue; | ||
825 | |||
826 | if (queue) | ||
827 | ath_dbg(common, ATH_DBG_MCI, | ||
828 | "MCI UNHALT BT GPM <queued>\n"); | ||
829 | else { | ||
830 | mci->halted_bt_gpm = false; | ||
831 | ath_dbg(common, ATH_DBG_MCI, | ||
832 | "MCI UNHALT BT GPM <sent>\n"); | ||
833 | } | ||
834 | } | ||
835 | |||
836 | if (*(((u8 *)payload) + MCI_GPM_COEX_B_HALT_STATE) == | ||
837 | MCI_GPM_COEX_BT_GPM_HALT) { | ||
838 | |||
839 | mci->halted_bt_gpm = !queue; | ||
840 | |||
841 | if (queue) | ||
842 | ath_dbg(common, ATH_DBG_MCI, | ||
843 | "MCI HALT BT GPM <not sent>\n"); | ||
844 | else | ||
845 | ath_dbg(common, ATH_DBG_MCI, | ||
846 | "MCI UNHALT BT GPM <sent>\n"); | ||
847 | } | ||
848 | |||
849 | break; | ||
850 | default: | ||
851 | break; | ||
852 | } | ||
853 | } | ||
854 | |||
855 | void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done) | ||
856 | { | ||
857 | struct ath_common *common = ath9k_hw_common(ah); | ||
858 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
859 | |||
860 | if (mci->update_2g5g) { | ||
861 | if (mci->is_2g) { | ||
862 | |||
863 | ar9003_mci_send_2g5g_status(ah, true); | ||
864 | ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA trans\n"); | ||
865 | ar9003_mci_send_lna_transfer(ah, true); | ||
866 | udelay(5); | ||
867 | |||
868 | REG_CLR_BIT(ah, AR_MCI_TX_CTRL, | ||
869 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); | ||
870 | |||
871 | if (AR_SREV_9462_20(ah)) { | ||
872 | REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL, | ||
873 | AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); | ||
874 | if (!(mci->config & | ||
875 | ATH_MCI_CONFIG_DISABLE_OSLA)) { | ||
876 | REG_SET_BIT(ah, AR_BTCOEX_CTRL, | ||
877 | AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); | ||
878 | } | ||
879 | } | ||
880 | } else { | ||
881 | ath_dbg(common, ATH_DBG_MCI, "MCI Send LNA take\n"); | ||
882 | ar9003_mci_send_lna_take(ah, true); | ||
883 | udelay(5); | ||
884 | |||
885 | REG_SET_BIT(ah, AR_MCI_TX_CTRL, | ||
886 | AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); | ||
887 | |||
888 | if (AR_SREV_9462_20(ah)) { | ||
889 | REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, | ||
890 | AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); | ||
891 | REG_CLR_BIT(ah, AR_BTCOEX_CTRL, | ||
892 | AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); | ||
893 | } | ||
894 | |||
895 | ar9003_mci_send_2g5g_status(ah, true); | ||
896 | } | ||
897 | } | ||
898 | } | ||
899 | |||
900 | bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, | ||
901 | u32 *payload, u8 len, bool wait_done, | ||
902 | bool check_bt) | ||
903 | { | ||
904 | struct ath_common *common = ath9k_hw_common(ah); | ||
905 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
906 | bool msg_sent = false; | ||
907 | u32 regval; | ||
908 | u32 saved_mci_int_en; | ||
909 | int i; | ||
910 | |||
911 | saved_mci_int_en = REG_READ(ah, AR_MCI_INTERRUPT_EN); | ||
912 | regval = REG_READ(ah, AR_BTCOEX_CTRL); | ||
913 | |||
914 | if ((regval == 0xdeadbeef) || !(regval & AR_BTCOEX_CTRL_MCI_MODE_EN)) { | ||
915 | |||
916 | ath_dbg(common, ATH_DBG_MCI, | ||
917 | "MCI Not sending 0x%x. MCI is not enabled. " | ||
918 | "full_sleep = %d\n", header, | ||
919 | (ah->power_mode == ATH9K_PM_FULL_SLEEP) ? 1 : 0); | ||
920 | |||
921 | ar9003_mci_queue_unsent_gpm(ah, header, payload, true); | ||
922 | return false; | ||
923 | |||
924 | } else if (check_bt && (mci->bt_state == MCI_BT_SLEEP)) { | ||
925 | |||
926 | ath_dbg(common, ATH_DBG_MCI, | ||
927 | "MCI Don't send message 0x%x. BT is in sleep state\n", header); | ||
928 | |||
929 | ar9003_mci_queue_unsent_gpm(ah, header, payload, true); | ||
930 | return false; | ||
931 | } | ||
932 | |||
933 | if (wait_done) | ||
934 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, 0); | ||
935 | |||
936 | /* Need to clear SW_MSG_DONE raw bit before wait */ | ||
937 | |||
938 | REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, | ||
939 | (AR_MCI_INTERRUPT_SW_MSG_DONE | | ||
940 | AR_MCI_INTERRUPT_MSG_FAIL_MASK)); | ||
941 | |||
942 | if (payload) { | ||
943 | for (i = 0; (i * 4) < len; i++) | ||
944 | REG_WRITE(ah, (AR_MCI_TX_PAYLOAD0 + i * 4), | ||
945 | *(payload + i)); | ||
946 | } | ||
947 | |||
948 | REG_WRITE(ah, AR_MCI_COMMAND0, | ||
949 | (SM((flag & MCI_FLAG_DISABLE_TIMESTAMP), | ||
950 | AR_MCI_COMMAND0_DISABLE_TIMESTAMP) | | ||
951 | SM(len, AR_MCI_COMMAND0_LEN) | | ||
952 | SM(header, AR_MCI_COMMAND0_HEADER))); | ||
953 | |||
954 | if (wait_done && | ||
955 | !(ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RAW, | ||
956 | AR_MCI_INTERRUPT_SW_MSG_DONE, 500))) | ||
957 | ar9003_mci_queue_unsent_gpm(ah, header, payload, true); | ||
958 | else { | ||
959 | ar9003_mci_queue_unsent_gpm(ah, header, payload, false); | ||
960 | msg_sent = true; | ||
961 | } | ||
962 | |||
963 | if (wait_done) | ||
964 | REG_WRITE(ah, AR_MCI_INTERRUPT_EN, saved_mci_int_en); | ||
965 | |||
966 | return msg_sent; | ||
967 | } | ||
968 | EXPORT_SYMBOL(ar9003_mci_send_message); | ||
969 | |||
970 | void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, | ||
971 | u16 len, u32 sched_addr) | ||
972 | { | ||
973 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
974 | void *sched_buf = (void *)((char *) gpm_buf + (sched_addr - gpm_addr)); | ||
975 | |||
976 | mci->gpm_addr = gpm_addr; | ||
977 | mci->gpm_buf = gpm_buf; | ||
978 | mci->gpm_len = len; | ||
979 | mci->sched_addr = sched_addr; | ||
980 | mci->sched_buf = sched_buf; | ||
981 | |||
982 | ar9003_mci_reset(ah, true, true, true); | ||
983 | } | ||
984 | EXPORT_SYMBOL(ar9003_mci_setup); | ||
985 | |||
986 | void ar9003_mci_cleanup(struct ath_hw *ah) | ||
987 | { | ||
988 | struct ath_common *common = ath9k_hw_common(ah); | ||
989 | |||
990 | /* Turn off MCI and Jupiter mode. */ | ||
991 | REG_WRITE(ah, AR_BTCOEX_CTRL, 0x00); | ||
992 | ath_dbg(common, ATH_DBG_MCI, "MCI ar9003_mci_cleanup\n"); | ||
993 | ar9003_mci_disable_interrupt(ah); | ||
994 | } | ||
995 | EXPORT_SYMBOL(ar9003_mci_cleanup); | ||
996 | |||
997 | static void ar9003_mci_process_gpm_extra(struct ath_hw *ah, u8 gpm_type, | ||
998 | u8 gpm_opcode, u32 *p_gpm) | ||
999 | { | ||
1000 | struct ath_common *common = ath9k_hw_common(ah); | ||
1001 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
1002 | u8 *p_data = (u8 *) p_gpm; | ||
1003 | |||
1004 | if (gpm_type != MCI_GPM_COEX_AGENT) | ||
1005 | return; | ||
1006 | |||
1007 | switch (gpm_opcode) { | ||
1008 | case MCI_GPM_COEX_VERSION_QUERY: | ||
1009 | ath_dbg(common, ATH_DBG_MCI, | ||
1010 | "MCI Recv GPM COEX Version Query\n"); | ||
1011 | ar9003_mci_send_coex_version_response(ah, true); | ||
1012 | break; | ||
1013 | case MCI_GPM_COEX_VERSION_RESPONSE: | ||
1014 | ath_dbg(common, ATH_DBG_MCI, | ||
1015 | "MCI Recv GPM COEX Version Response\n"); | ||
1016 | mci->bt_ver_major = | ||
1017 | *(p_data + MCI_GPM_COEX_B_MAJOR_VERSION); | ||
1018 | mci->bt_ver_minor = | ||
1019 | *(p_data + MCI_GPM_COEX_B_MINOR_VERSION); | ||
1020 | mci->bt_version_known = true; | ||
1021 | ath_dbg(common, ATH_DBG_MCI, | ||
1022 | "MCI BT Coex version: %d.%d\n", | ||
1023 | mci->bt_ver_major, | ||
1024 | mci->bt_ver_minor); | ||
1025 | break; | ||
1026 | case MCI_GPM_COEX_STATUS_QUERY: | ||
1027 | ath_dbg(common, ATH_DBG_MCI, | ||
1028 | "MCI Recv GPM COEX Status Query = 0x%02X.\n", | ||
1029 | *(p_data + MCI_GPM_COEX_B_WLAN_BITMAP)); | ||
1030 | mci->wlan_channels_update = true; | ||
1031 | ar9003_mci_send_coex_wlan_channels(ah, true); | ||
1032 | break; | ||
1033 | case MCI_GPM_COEX_BT_PROFILE_INFO: | ||
1034 | mci->query_bt = true; | ||
1035 | ath_dbg(common, ATH_DBG_MCI, | ||
1036 | "MCI Recv GPM COEX BT_Profile_Info\n"); | ||
1037 | break; | ||
1038 | case MCI_GPM_COEX_BT_STATUS_UPDATE: | ||
1039 | mci->query_bt = true; | ||
1040 | ath_dbg(common, ATH_DBG_MCI, | ||
1041 | "MCI Recv GPM COEX BT_Status_Update " | ||
1042 | "SEQ=%d (drop&query)\n", *(p_gpm + 3)); | ||
1043 | break; | ||
1044 | default: | ||
1045 | break; | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, | ||
1050 | u8 gpm_opcode, int time_out) | ||
1051 | { | ||
1052 | struct ath_common *common = ath9k_hw_common(ah); | ||
1053 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
1054 | u32 *p_gpm = NULL, mismatch = 0, more_data; | ||
1055 | u32 offset; | ||
1056 | u8 recv_type = 0, recv_opcode = 0; | ||
1057 | bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); | ||
1058 | |||
1059 | more_data = time_out ? MCI_GPM_NOMORE : MCI_GPM_MORE; | ||
1060 | |||
1061 | while (time_out > 0) { | ||
1062 | if (p_gpm) { | ||
1063 | MCI_GPM_RECYCLE(p_gpm); | ||
1064 | p_gpm = NULL; | ||
1065 | } | ||
1066 | |||
1067 | if (more_data != MCI_GPM_MORE) | ||
1068 | time_out = ar9003_mci_wait_for_interrupt(ah, | ||
1069 | AR_MCI_INTERRUPT_RX_MSG_RAW, | ||
1070 | AR_MCI_INTERRUPT_RX_MSG_GPM, | ||
1071 | time_out); | ||
1072 | |||
1073 | if (!time_out) | ||
1074 | break; | ||
1075 | |||
1076 | offset = ar9003_mci_state(ah, | ||
1077 | MCI_STATE_NEXT_GPM_OFFSET, &more_data); | ||
1078 | |||
1079 | if (offset == MCI_GPM_INVALID) | ||
1080 | continue; | ||
1081 | |||
1082 | p_gpm = (u32 *) (mci->gpm_buf + offset); | ||
1083 | recv_type = MCI_GPM_TYPE(p_gpm); | ||
1084 | recv_opcode = MCI_GPM_OPCODE(p_gpm); | ||
1085 | |||
1086 | if (MCI_GPM_IS_CAL_TYPE(recv_type)) { | ||
1087 | |||
1088 | if (recv_type == gpm_type) { | ||
1089 | |||
1090 | if ((gpm_type == MCI_GPM_BT_CAL_DONE) && | ||
1091 | !b_is_bt_cal_done) { | ||
1092 | gpm_type = MCI_GPM_BT_CAL_GRANT; | ||
1093 | ath_dbg(common, ATH_DBG_MCI, | ||
1094 | "MCI Recv BT_CAL_DONE" | ||
1095 | "wait BT_CAL_GRANT\n"); | ||
1096 | continue; | ||
1097 | } | ||
1098 | |||
1099 | break; | ||
1100 | } | ||
1101 | } else if ((recv_type == gpm_type) && | ||
1102 | (recv_opcode == gpm_opcode)) | ||
1103 | break; | ||
1104 | |||
1105 | /* not expected message */ | ||
1106 | |||
1107 | /* | ||
1108 | * check if it's cal_grant | ||
1109 | * | ||
1110 | * When we're waiting for cal_grant in reset routine, | ||
1111 | * it's possible that BT sends out cal_request at the | ||
1112 | * same time. Since BT's calibration doesn't happen | ||
1113 | * that often, we'll let BT completes calibration then | ||
1114 | * we continue to wait for cal_grant from BT. | ||
1115 | * Orginal: Wait BT_CAL_GRANT. | ||
1116 | * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait | ||
1117 | * BT_CAL_DONE -> Wait BT_CAL_GRANT. | ||
1118 | */ | ||
1119 | |||
1120 | if ((gpm_type == MCI_GPM_BT_CAL_GRANT) && | ||
1121 | (recv_type == MCI_GPM_BT_CAL_REQ)) { | ||
1122 | |||
1123 | u32 payload[4] = {0, 0, 0, 0}; | ||
1124 | |||
1125 | gpm_type = MCI_GPM_BT_CAL_DONE; | ||
1126 | ath_dbg(common, ATH_DBG_MCI, | ||
1127 | "MCI Rcv BT_CAL_REQ, send WLAN_CAL_GRANT\n"); | ||
1128 | |||
1129 | MCI_GPM_SET_CAL_TYPE(payload, | ||
1130 | MCI_GPM_WLAN_CAL_GRANT); | ||
1131 | |||
1132 | ar9003_mci_send_message(ah, MCI_GPM, 0, payload, 16, | ||
1133 | false, false); | ||
1134 | |||
1135 | ath_dbg(common, ATH_DBG_MCI, | ||
1136 | "MCI now wait for BT_CAL_DONE\n"); | ||
1137 | |||
1138 | continue; | ||
1139 | } else { | ||
1140 | ath_dbg(common, ATH_DBG_MCI, "MCI GPM subtype" | ||
1141 | "not match 0x%x\n", *(p_gpm + 1)); | ||
1142 | mismatch++; | ||
1143 | ar9003_mci_process_gpm_extra(ah, recv_type, | ||
1144 | recv_opcode, p_gpm); | ||
1145 | } | ||
1146 | } | ||
1147 | if (p_gpm) { | ||
1148 | MCI_GPM_RECYCLE(p_gpm); | ||
1149 | p_gpm = NULL; | ||
1150 | } | ||
1151 | |||
1152 | if (time_out <= 0) { | ||
1153 | time_out = 0; | ||
1154 | ath_dbg(common, ATH_DBG_MCI, | ||
1155 | "MCI GPM received timeout, mismatch = %d\n", mismatch); | ||
1156 | } else | ||
1157 | ath_dbg(common, ATH_DBG_MCI, | ||
1158 | "MCI Receive GPM type=0x%x, code=0x%x\n", | ||
1159 | gpm_type, gpm_opcode); | ||
1160 | |||
1161 | while (more_data == MCI_GPM_MORE) { | ||
1162 | |||
1163 | ath_dbg(common, ATH_DBG_MCI, "MCI discard remaining GPM\n"); | ||
1164 | offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, | ||
1165 | &more_data); | ||
1166 | |||
1167 | if (offset == MCI_GPM_INVALID) | ||
1168 | break; | ||
1169 | |||
1170 | p_gpm = (u32 *) (mci->gpm_buf + offset); | ||
1171 | recv_type = MCI_GPM_TYPE(p_gpm); | ||
1172 | recv_opcode = MCI_GPM_OPCODE(p_gpm); | ||
1173 | |||
1174 | if (!MCI_GPM_IS_CAL_TYPE(recv_type)) | ||
1175 | ar9003_mci_process_gpm_extra(ah, recv_type, | ||
1176 | recv_opcode, p_gpm); | ||
1177 | |||
1178 | MCI_GPM_RECYCLE(p_gpm); | ||
1179 | } | ||
1180 | |||
1181 | return time_out; | ||
1182 | } | ||
1183 | |||
1184 | u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) | ||
1185 | { | ||
1186 | struct ath_common *common = ath9k_hw_common(ah); | ||
1187 | struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; | ||
1188 | u32 value = 0, more_gpm = 0, gpm_ptr; | ||
1189 | u8 query_type; | ||
1190 | |||
1191 | switch (state_type) { | ||
1192 | case MCI_STATE_ENABLE: | ||
1193 | if (mci->ready) { | ||
1194 | |||
1195 | value = REG_READ(ah, AR_BTCOEX_CTRL); | ||
1196 | |||
1197 | if ((value == 0xdeadbeef) || (value == 0xffffffff)) | ||
1198 | value = 0; | ||
1199 | } | ||
1200 | value &= AR_BTCOEX_CTRL_MCI_MODE_EN; | ||
1201 | break; | ||
1202 | case MCI_STATE_INIT_GPM_OFFSET: | ||
1203 | value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); | ||
1204 | ath_dbg(common, ATH_DBG_MCI, | ||
1205 | "MCI GPM initial WRITE_PTR=%d\n", value); | ||
1206 | mci->gpm_idx = value; | ||
1207 | break; | ||
1208 | case MCI_STATE_NEXT_GPM_OFFSET: | ||
1209 | case MCI_STATE_LAST_GPM_OFFSET: | ||
1210 | /* | ||
1211 | * This could be useful to avoid new GPM message interrupt which | ||
1212 | * may lead to spurious interrupt after power sleep, or multiple | ||
1213 | * entry of ath_mci_intr(). | ||
1214 | * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can | ||
1215 | * alleviate this effect, but clearing GPM RX interrupt bit is | ||
1216 | * safe, because whether this is called from hw or driver code | ||
1217 | * there must be an interrupt bit set/triggered initially | ||
1218 | */ | ||
1219 | REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, | ||
1220 | AR_MCI_INTERRUPT_RX_MSG_GPM); | ||
1221 | |||
1222 | gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); | ||
1223 | value = gpm_ptr; | ||
1224 | |||
1225 | if (value == 0) | ||
1226 | value = mci->gpm_len - 1; | ||
1227 | else if (value >= mci->gpm_len) { | ||
1228 | if (value != 0xFFFF) { | ||
1229 | value = 0; | ||
1230 | ath_dbg(common, ATH_DBG_MCI, "MCI GPM offset" | ||
1231 | "out of range\n"); | ||
1232 | } | ||
1233 | } else | ||
1234 | value--; | ||
1235 | |||
1236 | if (value == 0xFFFF) { | ||
1237 | value = MCI_GPM_INVALID; | ||
1238 | more_gpm = MCI_GPM_NOMORE; | ||
1239 | ath_dbg(common, ATH_DBG_MCI, "MCI GPM ptr invalid" | ||
1240 | "@ptr=%d, offset=%d, more=GPM_NOMORE\n", | ||
1241 | gpm_ptr, value); | ||
1242 | } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) { | ||
1243 | |||
1244 | if (gpm_ptr == mci->gpm_idx) { | ||
1245 | value = MCI_GPM_INVALID; | ||
1246 | more_gpm = MCI_GPM_NOMORE; | ||
1247 | |||
1248 | ath_dbg(common, ATH_DBG_MCI, "MCI GPM message" | ||
1249 | "not available @ptr=%d, @offset=%d," | ||
1250 | "more=GPM_NOMORE\n", gpm_ptr, value); | ||
1251 | } else { | ||
1252 | for (;;) { | ||
1253 | |||
1254 | u32 temp_index; | ||
1255 | |||
1256 | /* skip reserved GPM if any */ | ||
1257 | |||
1258 | if (value != mci->gpm_idx) | ||
1259 | more_gpm = MCI_GPM_MORE; | ||
1260 | else | ||
1261 | more_gpm = MCI_GPM_NOMORE; | ||
1262 | |||
1263 | temp_index = mci->gpm_idx; | ||
1264 | mci->gpm_idx++; | ||
1265 | |||
1266 | if (mci->gpm_idx >= | ||
1267 | mci->gpm_len) | ||
1268 | mci->gpm_idx = 0; | ||
1269 | |||
1270 | ath_dbg(common, ATH_DBG_MCI, | ||
1271 | "MCI GPM message got ptr=%d," | ||
1272 | "@offset=%d, more=%d\n", | ||
1273 | gpm_ptr, temp_index, | ||
1274 | (more_gpm == MCI_GPM_MORE)); | ||
1275 | |||
1276 | if (ar9003_mci_is_gpm_valid(ah, | ||
1277 | temp_index)) { | ||
1278 | value = temp_index; | ||
1279 | break; | ||
1280 | } | ||
1281 | |||
1282 | if (more_gpm == MCI_GPM_NOMORE) { | ||
1283 | value = MCI_GPM_INVALID; | ||
1284 | break; | ||
1285 | } | ||
1286 | } | ||
1287 | } | ||
1288 | if (p_data) | ||
1289 | *p_data = more_gpm; | ||
1290 | } | ||
1291 | |||
1292 | if (value != MCI_GPM_INVALID) | ||
1293 | value <<= 4; | ||
1294 | |||
1295 | break; | ||
1296 | case MCI_STATE_LAST_SCHD_MSG_OFFSET: | ||
1297 | value = MS(REG_READ(ah, AR_MCI_RX_STATUS), | ||
1298 | AR_MCI_RX_LAST_SCHD_MSG_INDEX); | ||
1299 | /* Make it in bytes */ | ||
1300 | value <<= 4; | ||
1301 | break; | ||
1302 | |||
1303 | case MCI_STATE_REMOTE_SLEEP: | ||
1304 | value = MS(REG_READ(ah, AR_MCI_RX_STATUS), | ||
1305 | AR_MCI_RX_REMOTE_SLEEP) ? | ||
1306 | MCI_BT_SLEEP : MCI_BT_AWAKE; | ||
1307 | break; | ||
1308 | |||
1309 | case MCI_STATE_CONT_RSSI_POWER: | ||
1310 | value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER); | ||
1311 | break; | ||
1312 | |||
1313 | case MCI_STATE_CONT_PRIORITY: | ||
1314 | value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY); | ||
1315 | break; | ||
1316 | |||
1317 | case MCI_STATE_CONT_TXRX: | ||
1318 | value = MS(mci->cont_status, AR_MCI_CONT_TXRX); | ||
1319 | break; | ||
1320 | |||
1321 | case MCI_STATE_BT: | ||
1322 | value = mci->bt_state; | ||
1323 | break; | ||
1324 | |||
1325 | case MCI_STATE_SET_BT_SLEEP: | ||
1326 | mci->bt_state = MCI_BT_SLEEP; | ||
1327 | break; | ||
1328 | |||
1329 | case MCI_STATE_SET_BT_AWAKE: | ||
1330 | mci->bt_state = MCI_BT_AWAKE; | ||
1331 | ar9003_mci_send_coex_version_query(ah, true); | ||
1332 | ar9003_mci_send_coex_wlan_channels(ah, true); | ||
1333 | |||
1334 | if (mci->unhalt_bt_gpm) { | ||
1335 | |||
1336 | ath_dbg(common, ATH_DBG_MCI, | ||
1337 | "MCI unhalt BT GPM\n"); | ||
1338 | ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); | ||
1339 | } | ||
1340 | |||
1341 | ar9003_mci_2g5g_switch(ah, true); | ||
1342 | break; | ||
1343 | |||
1344 | case MCI_STATE_SET_BT_CAL_START: | ||
1345 | mci->bt_state = MCI_BT_CAL_START; | ||
1346 | break; | ||
1347 | |||
1348 | case MCI_STATE_SET_BT_CAL: | ||
1349 | mci->bt_state = MCI_BT_CAL; | ||
1350 | break; | ||
1351 | |||
1352 | case MCI_STATE_RESET_REQ_WAKE: | ||
1353 | ar9003_mci_reset_req_wakeup(ah); | ||
1354 | mci->update_2g5g = true; | ||
1355 | |||
1356 | if ((AR_SREV_9462_20_OR_LATER(ah)) && | ||
1357 | (mci->config & ATH_MCI_CONFIG_MCI_OBS_MASK)) { | ||
1358 | /* Check if we still have control of the GPIOs */ | ||
1359 | if ((REG_READ(ah, AR_GLB_GPIO_CONTROL) & | ||
1360 | ATH_MCI_CONFIG_MCI_OBS_GPIO) != | ||
1361 | ATH_MCI_CONFIG_MCI_OBS_GPIO) { | ||
1362 | |||
1363 | ath_dbg(common, ATH_DBG_MCI, | ||
1364 | "MCI reconfigure observation"); | ||
1365 | ar9003_mci_observation_set_up(ah); | ||
1366 | } | ||
1367 | } | ||
1368 | break; | ||
1369 | |||
1370 | case MCI_STATE_SEND_WLAN_COEX_VERSION: | ||
1371 | ar9003_mci_send_coex_version_response(ah, true); | ||
1372 | break; | ||
1373 | |||
1374 | case MCI_STATE_SET_BT_COEX_VERSION: | ||
1375 | |||
1376 | if (!p_data) | ||
1377 | ath_dbg(common, ATH_DBG_MCI, | ||
1378 | "MCI Set BT Coex version with NULL data!!\n"); | ||
1379 | else { | ||
1380 | mci->bt_ver_major = (*p_data >> 8) & 0xff; | ||
1381 | mci->bt_ver_minor = (*p_data) & 0xff; | ||
1382 | mci->bt_version_known = true; | ||
1383 | ath_dbg(common, ATH_DBG_MCI, | ||
1384 | "MCI BT version set: %d.%d\n", | ||
1385 | mci->bt_ver_major, | ||
1386 | mci->bt_ver_minor); | ||
1387 | } | ||
1388 | break; | ||
1389 | |||
1390 | case MCI_STATE_SEND_WLAN_CHANNELS: | ||
1391 | if (p_data) { | ||
1392 | if (((mci->wlan_channels[1] & 0xffff0000) == | ||
1393 | (*(p_data + 1) & 0xffff0000)) && | ||
1394 | (mci->wlan_channels[2] == *(p_data + 2)) && | ||
1395 | (mci->wlan_channels[3] == *(p_data + 3))) | ||
1396 | break; | ||
1397 | |||
1398 | mci->wlan_channels[0] = *p_data++; | ||
1399 | mci->wlan_channels[1] = *p_data++; | ||
1400 | mci->wlan_channels[2] = *p_data++; | ||
1401 | mci->wlan_channels[3] = *p_data++; | ||
1402 | } | ||
1403 | mci->wlan_channels_update = true; | ||
1404 | ar9003_mci_send_coex_wlan_channels(ah, true); | ||
1405 | break; | ||
1406 | |||
1407 | case MCI_STATE_SEND_VERSION_QUERY: | ||
1408 | ar9003_mci_send_coex_version_query(ah, true); | ||
1409 | break; | ||
1410 | |||
1411 | case MCI_STATE_SEND_STATUS_QUERY: | ||
1412 | query_type = (AR_SREV_9462_10(ah)) ? | ||
1413 | MCI_GPM_COEX_QUERY_BT_ALL_INFO : | ||
1414 | MCI_GPM_COEX_QUERY_BT_TOPOLOGY; | ||
1415 | |||
1416 | ar9003_mci_send_coex_bt_status_query(ah, true, query_type); | ||
1417 | break; | ||
1418 | |||
1419 | case MCI_STATE_NEED_FLUSH_BT_INFO: | ||
1420 | /* | ||
1421 | * btcoex_hw.mci.unhalt_bt_gpm means whether it's | ||
1422 | * needed to send UNHALT message. It's set whenever | ||
1423 | * there's a request to send HALT message. | ||
1424 | * mci_halted_bt_gpm means whether HALT message is sent | ||
1425 | * out successfully. | ||
1426 | * | ||
1427 | * Checking (mci_unhalt_bt_gpm == false) instead of | ||
1428 | * checking (ah->mci_halted_bt_gpm == false) will make | ||
1429 | * sure currently is in UNHALT-ed mode and BT can | ||
1430 | * respond to status query. | ||
1431 | */ | ||
1432 | value = (!mci->unhalt_bt_gpm && | ||
1433 | mci->need_flush_btinfo) ? 1 : 0; | ||
1434 | if (p_data) | ||
1435 | mci->need_flush_btinfo = | ||
1436 | (*p_data != 0) ? true : false; | ||
1437 | break; | ||
1438 | |||
1439 | case MCI_STATE_RECOVER_RX: | ||
1440 | |||
1441 | ath_dbg(common, ATH_DBG_MCI, "MCI hw RECOVER_RX\n"); | ||
1442 | ar9003_mci_prep_interface(ah); | ||
1443 | mci->query_bt = true; | ||
1444 | mci->need_flush_btinfo = true; | ||
1445 | ar9003_mci_send_coex_wlan_channels(ah, true); | ||
1446 | ar9003_mci_2g5g_switch(ah, true); | ||
1447 | break; | ||
1448 | |||
1449 | case MCI_STATE_NEED_FTP_STOMP: | ||
1450 | value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); | ||
1451 | break; | ||
1452 | |||
1453 | case MCI_STATE_NEED_TUNING: | ||
1454 | value = !(mci->config & ATH_MCI_CONFIG_DISABLE_TUNING); | ||
1455 | break; | ||
1456 | |||
1457 | default: | ||
1458 | break; | ||
1459 | |||
1460 | } | ||
1461 | |||
1462 | return value; | ||
1463 | } | ||
1464 | EXPORT_SYMBOL(ar9003_mci_state); | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index cd43d5904567..c9c3b1889965 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -1203,6 +1203,32 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); | |||
1203 | void ath9k_hw_proc_mib_event(struct ath_hw *ah); | 1203 | void ath9k_hw_proc_mib_event(struct ath_hw *ah); |
1204 | void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); | 1204 | void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); |
1205 | 1205 | ||
1206 | bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, | ||
1207 | u32 *payload, u8 len, bool wait_done, | ||
1208 | bool check_bt); | ||
1209 | void ar9003_mci_mute_bt(struct ath_hw *ah); | ||
1210 | u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data); | ||
1211 | void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, | ||
1212 | u16 len, u32 sched_addr); | ||
1213 | void ar9003_mci_cleanup(struct ath_hw *ah); | ||
1214 | void ar9003_mci_send_coex_halt_bt_gpm(struct ath_hw *ah, bool halt, | ||
1215 | bool wait_done); | ||
1216 | u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, | ||
1217 | u8 gpm_opcode, int time_out); | ||
1218 | void ar9003_mci_2g5g_changed(struct ath_hw *ah, bool is_2g); | ||
1219 | void ar9003_mci_disable_interrupt(struct ath_hw *ah); | ||
1220 | void ar9003_mci_enable_interrupt(struct ath_hw *ah); | ||
1221 | void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done); | ||
1222 | void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, | ||
1223 | bool is_full_sleep); | ||
1224 | bool ar9003_mci_check_int(struct ath_hw *ah, u32 ints); | ||
1225 | void ar9003_mci_remote_reset(struct ath_hw *ah, bool wait_done); | ||
1226 | void ar9003_mci_send_sys_waking(struct ath_hw *ah, bool wait_done); | ||
1227 | void ar9003_mci_send_lna_transfer(struct ath_hw *ah, bool wait_done); | ||
1228 | void ar9003_mci_sync_bt_state(struct ath_hw *ah); | ||
1229 | void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, | ||
1230 | u32 *rx_msg_intr); | ||
1231 | |||
1206 | #define ATH9K_CLOCK_RATE_CCK 22 | 1232 | #define ATH9K_CLOCK_RATE_CCK 22 |
1207 | #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 | 1233 | #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 |
1208 | #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 | 1234 | #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 |