blob: 3da6ac60c65d030176292c49ea5d671de4f67052 [file] [log] [blame]
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001/*
2 * This file is part of wl18xx
3 *
4 * Copyright (C) 2011 Texas Instruments
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/platform_device.h>
Arik Nemtsov2fc28de2012-05-10 12:13:27 +030024#include <linux/ip.h>
Luciano Coelho640dfb9b2012-06-07 23:39:28 +030025#include <linux/firmware.h>
Luciano Coelhobc2ab3b2013-05-08 12:54:56 +030026#include <linux/etherdevice.h>
Eyal Reizerbd763482015-04-29 17:50:03 +030027#include <linux/irq.h>
Luciano Coelho9a1a6992012-05-10 12:13:06 +030028
29#include "../wlcore/wlcore.h"
30#include "../wlcore/debug.h"
Luciano Coelho46a1d512012-05-10 12:13:12 +030031#include "../wlcore/io.h"
32#include "../wlcore/acx.h"
Arik Nemtsovfb0f2e42012-05-10 12:13:18 +030033#include "../wlcore/tx.h"
Arik Nemtsov9c809f82012-05-10 12:13:23 +030034#include "../wlcore/rx.h"
Luciano Coelho46a1d512012-05-10 12:13:12 +030035#include "../wlcore/boot.h"
Luciano Coelho9a1a6992012-05-10 12:13:06 +030036
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +030037#include "reg.h"
Luciano Coelho46a1d512012-05-10 12:13:12 +030038#include "conf.h"
Eliad Pellerfcab1892012-11-22 18:06:18 +020039#include "cmd.h"
Luciano Coelhob8422dc2012-05-10 12:13:26 +030040#include "acx.h"
Arik Nemtsov872b3452012-05-10 12:13:25 +030041#include "tx.h"
Luciano Coelho274c66c2012-05-10 12:13:13 +030042#include "wl18xx.h"
Luciano Coelhobe652022012-05-10 12:13:41 +030043#include "io.h"
Eliad Peller78e28062012-11-22 18:06:15 +020044#include "scan.h"
Eliad Pellerc50a2822012-11-22 18:06:19 +020045#include "event.h"
Luciano Coelho8c0ea102012-05-10 12:14:09 +030046#include "debugfs.h"
Arik Nemtsov1349c422012-05-10 12:13:16 +030047
Arik Nemtsov169da042012-05-10 12:13:28 +030048#define WL18XX_RX_CHECKSUM_MASK 0x40
49
Yair Shapirac68cc0f2012-07-05 15:11:30 +000050static char *ht_mode_param = NULL;
51static char *board_type_param = NULL;
Assaf Azulay3d62eb52012-05-10 12:14:23 +030052static bool checksum_param = false;
Arik Nemtsov09aad142012-06-10 22:57:30 +030053static int num_rx_desc_param = -1;
Arik Nemtsov17d97712012-05-29 12:44:12 +030054
55/* phy paramters */
56static int dc2dc_param = -1;
57static int n_antennas_2_param = -1;
58static int n_antennas_5_param = -1;
59static int low_band_component_param = -1;
60static int low_band_component_type_param = -1;
61static int high_band_component_param = -1;
62static int high_band_component_type_param = -1;
63static int pwr_limit_reference_11_abg_param = -1;
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +030064
Arik Nemtsovf648eab2012-05-10 12:13:20 +030065static const u8 wl18xx_rate_to_idx_2ghz[] = {
66 /* MCS rates are used only with 11n */
67 15, /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
68 14, /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
69 13, /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
70 12, /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
71 11, /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
72 10, /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
73 9, /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
74 8, /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
75 7, /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
76 6, /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
77 5, /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
78 4, /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
79 3, /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
80 2, /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
81 1, /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
82 0, /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
83
84 11, /* WL18XX_CONF_HW_RXTX_RATE_54 */
85 10, /* WL18XX_CONF_HW_RXTX_RATE_48 */
86 9, /* WL18XX_CONF_HW_RXTX_RATE_36 */
87 8, /* WL18XX_CONF_HW_RXTX_RATE_24 */
88
89 /* TI-specific rate */
90 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22 */
91
92 7, /* WL18XX_CONF_HW_RXTX_RATE_18 */
93 6, /* WL18XX_CONF_HW_RXTX_RATE_12 */
94 3, /* WL18XX_CONF_HW_RXTX_RATE_11 */
95 5, /* WL18XX_CONF_HW_RXTX_RATE_9 */
96 4, /* WL18XX_CONF_HW_RXTX_RATE_6 */
97 2, /* WL18XX_CONF_HW_RXTX_RATE_5_5 */
98 1, /* WL18XX_CONF_HW_RXTX_RATE_2 */
99 0 /* WL18XX_CONF_HW_RXTX_RATE_1 */
100};
101
102static const u8 wl18xx_rate_to_idx_5ghz[] = {
103 /* MCS rates are used only with 11n */
104 15, /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
105 14, /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
106 13, /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
107 12, /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
108 11, /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
109 10, /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
110 9, /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
111 8, /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
112 7, /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
113 6, /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
114 5, /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
115 4, /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
116 3, /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
117 2, /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
118 1, /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
119 0, /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
120
121 7, /* WL18XX_CONF_HW_RXTX_RATE_54 */
122 6, /* WL18XX_CONF_HW_RXTX_RATE_48 */
123 5, /* WL18XX_CONF_HW_RXTX_RATE_36 */
124 4, /* WL18XX_CONF_HW_RXTX_RATE_24 */
125
126 /* TI-specific rate */
127 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22 */
128
129 3, /* WL18XX_CONF_HW_RXTX_RATE_18 */
130 2, /* WL18XX_CONF_HW_RXTX_RATE_12 */
131 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_11 */
132 1, /* WL18XX_CONF_HW_RXTX_RATE_9 */
133 0, /* WL18XX_CONF_HW_RXTX_RATE_6 */
134 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_5_5 */
135 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_2 */
136 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_1 */
137};
138
139static const u8 *wl18xx_band_rate_to_idx[] = {
140 [IEEE80211_BAND_2GHZ] = wl18xx_rate_to_idx_2ghz,
141 [IEEE80211_BAND_5GHZ] = wl18xx_rate_to_idx_5ghz
142};
143
144enum wl18xx_hw_rates {
145 WL18XX_CONF_HW_RXTX_RATE_MCS15 = 0,
146 WL18XX_CONF_HW_RXTX_RATE_MCS14,
147 WL18XX_CONF_HW_RXTX_RATE_MCS13,
148 WL18XX_CONF_HW_RXTX_RATE_MCS12,
149 WL18XX_CONF_HW_RXTX_RATE_MCS11,
150 WL18XX_CONF_HW_RXTX_RATE_MCS10,
151 WL18XX_CONF_HW_RXTX_RATE_MCS9,
152 WL18XX_CONF_HW_RXTX_RATE_MCS8,
153 WL18XX_CONF_HW_RXTX_RATE_MCS7,
154 WL18XX_CONF_HW_RXTX_RATE_MCS6,
155 WL18XX_CONF_HW_RXTX_RATE_MCS5,
156 WL18XX_CONF_HW_RXTX_RATE_MCS4,
157 WL18XX_CONF_HW_RXTX_RATE_MCS3,
158 WL18XX_CONF_HW_RXTX_RATE_MCS2,
159 WL18XX_CONF_HW_RXTX_RATE_MCS1,
160 WL18XX_CONF_HW_RXTX_RATE_MCS0,
161 WL18XX_CONF_HW_RXTX_RATE_54,
162 WL18XX_CONF_HW_RXTX_RATE_48,
163 WL18XX_CONF_HW_RXTX_RATE_36,
164 WL18XX_CONF_HW_RXTX_RATE_24,
165 WL18XX_CONF_HW_RXTX_RATE_22,
166 WL18XX_CONF_HW_RXTX_RATE_18,
167 WL18XX_CONF_HW_RXTX_RATE_12,
168 WL18XX_CONF_HW_RXTX_RATE_11,
169 WL18XX_CONF_HW_RXTX_RATE_9,
170 WL18XX_CONF_HW_RXTX_RATE_6,
171 WL18XX_CONF_HW_RXTX_RATE_5_5,
172 WL18XX_CONF_HW_RXTX_RATE_2,
173 WL18XX_CONF_HW_RXTX_RATE_1,
174 WL18XX_CONF_HW_RXTX_RATE_MAX,
175};
176
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300177static struct wlcore_conf wl18xx_conf = {
178 .sg = {
179 .params = {
180 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
181 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
182 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
183 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
184 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
185 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
186 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
187 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
188 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
189 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
190 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
191 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
192 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
193 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
194 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
195 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
196 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
197 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
198 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
199 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
200 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
201 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
202 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
203 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
204 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
205 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
206 /* active scan params */
207 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
208 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
209 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
210 /* passive scan params */
211 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
212 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
213 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
214 /* passive scan in dual antenna params */
215 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
216 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
217 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
218 /* general params */
219 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
220 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
221 [CONF_SG_BEACON_MISS_PERCENT] = 60,
222 [CONF_SG_DHCP_TIME] = 5000,
223 [CONF_SG_RXT] = 1200,
224 [CONF_SG_TXT] = 1000,
225 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
226 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
227 [CONF_SG_HV3_MAX_SERVED] = 6,
228 [CONF_SG_PS_POLL_TIMEOUT] = 10,
229 [CONF_SG_UPSD_TIMEOUT] = 10,
230 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
231 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
232 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
233 /* AP params */
234 [CONF_AP_BEACON_MISS_TX] = 3,
235 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
236 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
237 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
238 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
239 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
240 /* CTS Diluting params */
241 [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
242 [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
243 },
244 .state = CONF_SG_PROTECTIVE,
245 },
246 .rx = {
247 .rx_msdu_life_time = 512000,
248 .packet_detection_threshold = 0,
249 .ps_poll_timeout = 15,
250 .upsd_timeout = 15,
251 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
252 .rx_cca_threshold = 0,
253 .irq_blk_threshold = 0xFFFF,
254 .irq_pkt_threshold = 0,
255 .irq_timeout = 600,
256 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
257 },
258 .tx = {
259 .tx_energy_detection = 0,
260 .sta_rc_conf = {
261 .enabled_rates = 0,
262 .short_retry_limit = 10,
263 .long_retry_limit = 10,
264 .aflags = 0,
265 },
266 .ac_conf_count = 4,
267 .ac_conf = {
268 [CONF_TX_AC_BE] = {
269 .ac = CONF_TX_AC_BE,
270 .cw_min = 15,
271 .cw_max = 63,
272 .aifsn = 3,
273 .tx_op_limit = 0,
274 },
275 [CONF_TX_AC_BK] = {
276 .ac = CONF_TX_AC_BK,
277 .cw_min = 15,
278 .cw_max = 63,
279 .aifsn = 7,
280 .tx_op_limit = 0,
281 },
282 [CONF_TX_AC_VI] = {
283 .ac = CONF_TX_AC_VI,
284 .cw_min = 15,
285 .cw_max = 63,
286 .aifsn = CONF_TX_AIFS_PIFS,
287 .tx_op_limit = 3008,
288 },
289 [CONF_TX_AC_VO] = {
290 .ac = CONF_TX_AC_VO,
291 .cw_min = 15,
292 .cw_max = 63,
293 .aifsn = CONF_TX_AIFS_PIFS,
294 .tx_op_limit = 1504,
295 },
296 },
297 .max_tx_retries = 100,
298 .ap_aging_period = 300,
299 .tid_conf_count = 4,
300 .tid_conf = {
301 [CONF_TX_AC_BE] = {
302 .queue_id = CONF_TX_AC_BE,
303 .channel_type = CONF_CHANNEL_TYPE_EDCF,
304 .tsid = CONF_TX_AC_BE,
305 .ps_scheme = CONF_PS_SCHEME_LEGACY,
306 .ack_policy = CONF_ACK_POLICY_LEGACY,
307 .apsd_conf = {0, 0},
308 },
309 [CONF_TX_AC_BK] = {
310 .queue_id = CONF_TX_AC_BK,
311 .channel_type = CONF_CHANNEL_TYPE_EDCF,
312 .tsid = CONF_TX_AC_BK,
313 .ps_scheme = CONF_PS_SCHEME_LEGACY,
314 .ack_policy = CONF_ACK_POLICY_LEGACY,
315 .apsd_conf = {0, 0},
316 },
317 [CONF_TX_AC_VI] = {
318 .queue_id = CONF_TX_AC_VI,
319 .channel_type = CONF_CHANNEL_TYPE_EDCF,
320 .tsid = CONF_TX_AC_VI,
321 .ps_scheme = CONF_PS_SCHEME_LEGACY,
322 .ack_policy = CONF_ACK_POLICY_LEGACY,
323 .apsd_conf = {0, 0},
324 },
325 [CONF_TX_AC_VO] = {
326 .queue_id = CONF_TX_AC_VO,
327 .channel_type = CONF_CHANNEL_TYPE_EDCF,
328 .tsid = CONF_TX_AC_VO,
329 .ps_scheme = CONF_PS_SCHEME_LEGACY,
330 .ack_policy = CONF_ACK_POLICY_LEGACY,
331 .apsd_conf = {0, 0},
332 },
333 },
334 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
335 .tx_compl_timeout = 350,
336 .tx_compl_threshold = 10,
337 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
338 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
339 .tmpl_short_retry_limit = 10,
340 .tmpl_long_retry_limit = 10,
341 .tx_watchdog_timeout = 5000,
Arik Nemtsov0e810472012-11-27 08:45:00 +0200342 .slow_link_thold = 3,
343 .fast_link_thold = 30,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300344 },
345 .conn = {
346 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
347 .listen_interval = 1,
348 .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
349 .suspend_listen_interval = 3,
350 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Eliad Peller186b5a72012-05-15 16:35:20 +0300351 .bcn_filt_ie_count = 3,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300352 .bcn_filt_ie = {
353 [0] = {
354 .ie = WLAN_EID_CHANNEL_SWITCH,
355 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
356 },
357 [1] = {
358 .ie = WLAN_EID_HT_OPERATION,
359 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
360 },
Eliad Peller186b5a72012-05-15 16:35:20 +0300361 [2] = {
362 .ie = WLAN_EID_ERP_INFO,
363 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
364 },
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300365 },
Igal Chernobelsky7b052212012-05-15 17:08:57 +0300366 .synch_fail_thold = 12,
367 .bss_lose_timeout = 400,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300368 .beacon_rx_timeout = 10000,
369 .broadcast_timeout = 20000,
370 .rx_broadcast_in_ps = 1,
371 .ps_poll_threshold = 10,
372 .bet_enable = CONF_BET_MODE_ENABLE,
373 .bet_max_consecutive = 50,
374 .psm_entry_retries = 8,
375 .psm_exit_retries = 16,
376 .psm_entry_nullfunc_retries = 3,
Arik Nemtsov0fc1d2e2012-07-03 11:34:43 +0300377 .dynamic_ps_timeout = 1500,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300378 .forced_ps = false,
379 .keep_alive_interval = 55000,
380 .max_listen_interval = 20,
Arik Nemtsov66340e52012-06-10 17:09:22 +0300381 .sta_sleep_auth = WL1271_PSM_ILLEGAL,
Ram Amrani6d5a7482014-12-29 08:24:04 +0200382 .suspend_rx_ba_activity = 0,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300383 },
384 .itrim = {
385 .enable = false,
386 .timeout = 50000,
387 },
388 .pm_config = {
389 .host_clk_settling_time = 5000,
Luciano Coelho648f6ed2012-06-07 23:39:24 +0300390 .host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300391 },
392 .roam_trigger = {
393 .trigger_pacing = 1,
394 .avg_weight_rssi_beacon = 20,
395 .avg_weight_rssi_data = 10,
396 .avg_weight_snr_beacon = 20,
397 .avg_weight_snr_data = 10,
398 },
399 .scan = {
400 .min_dwell_time_active = 7500,
401 .max_dwell_time_active = 30000,
Eyal Shapira5d3a1602012-12-08 02:58:23 +0200402 .min_dwell_time_active_long = 25000,
403 .max_dwell_time_active_long = 50000,
Eliad Peller7c482c12012-11-26 18:05:40 +0200404 .dwell_time_passive = 100000,
405 .dwell_time_dfs = 150000,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300406 .num_probe_reqs = 2,
407 .split_scan_timeout = 50000,
408 },
409 .sched_scan = {
410 /*
411 * Values are in TU/1000 but since sched scan FW command
412 * params are in TUs rounding up may occur.
413 */
414 .base_dwell_time = 7500,
415 .max_dwell_time_delta = 22500,
416 /* based on 250bits per probe @1Mbps */
417 .dwell_time_delta_per_probe = 2000,
418 /* based on 250bits per probe @6Mbps (plus a bit more) */
419 .dwell_time_delta_per_probe_5 = 350,
420 .dwell_time_passive = 100000,
421 .dwell_time_dfs = 150000,
422 .num_probe_reqs = 2,
423 .rssi_threshold = -90,
424 .snr_threshold = 0,
425 },
426 .ht = {
Ido Reis9ae48ae2012-06-25 18:51:54 +0300427 .rx_ba_win_size = 32,
Luciano Coelho3507efa2012-05-10 12:14:21 +0300428 .tx_ba_win_size = 64,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300429 .inactivity_timeout = 10000,
430 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
431 },
432 .mem = {
433 .num_stations = 1,
434 .ssid_profiles = 1,
435 .rx_block_num = 40,
436 .tx_min_block_num = 40,
437 .dynamic_memory = 1,
438 .min_req_tx_blocks = 45,
439 .min_req_rx_blocks = 22,
440 .tx_min = 27,
441 },
442 .fm_coex = {
443 .enable = true,
444 .swallow_period = 5,
445 .n_divider_fref_set_1 = 0xff, /* default */
446 .n_divider_fref_set_2 = 12,
Victor Goldenshtein461b9582012-05-15 17:15:40 +0300447 .m_divider_fref_set_1 = 0xffff,
448 .m_divider_fref_set_2 = 148, /* default */
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300449 .coex_pll_stabilization_time = 0xffffffff, /* default */
450 .ldo_stabilization_time = 0xffff, /* default */
451 .fm_disturbed_band_margin = 0xff, /* default */
452 .swallow_clk_diff = 0xff, /* default */
453 },
454 .rx_streaming = {
455 .duration = 150,
456 .queues = 0x1,
457 .interval = 20,
458 .always = 0,
459 },
460 .fwlog = {
Ido Reis9d8146d2013-09-09 12:24:37 +0300461 .mode = WL12XX_FWLOG_CONTINUOUS,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300462 .mem_blocks = 2,
463 .severity = 0,
464 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
Ido Reis9d8146d2013-09-09 12:24:37 +0300465 .output = WL12XX_FWLOG_OUTPUT_DBG_PINS,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300466 .threshold = 0,
467 },
468 .rate = {
469 .rate_retry_score = 32000,
470 .per_add = 8192,
471 .per_th1 = 2048,
472 .per_th2 = 4096,
473 .max_per = 8100,
474 .inverse_curiosity_factor = 5,
475 .tx_fail_low_th = 4,
476 .tx_fail_high_th = 10,
477 .per_alpha_shift = 4,
478 .per_add_shift = 13,
479 .per_beta1_shift = 10,
480 .per_beta2_shift = 8,
481 .rate_check_up = 2,
482 .rate_check_down = 12,
483 .rate_retry_policy = {
484 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x00, 0x00, 0x00, 0x00, 0x00,
486 0x00, 0x00, 0x00,
487 },
488 },
489 .hangover = {
490 .recover_time = 0,
491 .hangover_period = 20,
492 .dynamic_mode = 1,
493 .early_termination_mode = 1,
494 .max_period = 20,
495 .min_period = 1,
496 .increase_delta = 1,
497 .decrease_delta = 2,
498 .quiet_time = 4,
499 .increase_time = 1,
500 .window_size = 16,
501 },
Yair Shapira72303412012-11-26 18:05:50 +0200502 .recovery = {
503 .bug_on_recovery = 0,
504 .no_recovery = 0,
505 },
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300506};
507
508static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
Yair Shapirac68cc0f2012-07-05 15:11:30 +0000509 .ht = {
Igal Chernobelsky50e4c902013-09-09 12:24:32 +0300510 .mode = HT_MODE_WIDE,
Yair Shapirac68cc0f2012-07-05 15:11:30 +0000511 },
Luciano Coelho46a1d512012-05-10 12:13:12 +0300512 .phy = {
513 .phy_standalone = 0x00,
514 .primary_clock_setting_time = 0x05,
515 .clock_valid_on_wake_up = 0x00,
516 .secondary_clock_setting_time = 0x05,
Yair Shapirac68cc0f2012-07-05 15:11:30 +0000517 .board_type = BOARD_TYPE_HDK_18XX,
Luciano Coelho46a1d512012-05-10 12:13:12 +0300518 .auto_detect = 0x00,
519 .dedicated_fem = FEM_NONE,
Ido Reise1c497c2012-07-13 00:12:08 +0300520 .low_band_component = COMPONENT_3_WAY_SWITCH,
Igal Chernobelsky50e4c902013-09-09 12:24:32 +0300521 .low_band_component_type = 0x05,
Luciano Coelho46a1d512012-05-10 12:13:12 +0300522 .high_band_component = COMPONENT_2_WAY_SWITCH,
523 .high_band_component_type = 0x09,
Luciano Coelho46a1d512012-05-10 12:13:12 +0300524 .tcxo_ldo_voltage = 0x00,
525 .xtal_itrim_val = 0x04,
526 .srf_state = 0x00,
527 .io_configuration = 0x01,
528 .sdio_configuration = 0x00,
529 .settings = 0x00,
530 .enable_clpc = 0x00,
531 .enable_tx_low_pwr_on_siso_rdl = 0x00,
532 .rx_profile = 0x00,
Yair Shapirad88949b2012-11-27 08:44:43 +0200533 .pwr_limit_reference_11_abg = 0x64,
534 .per_chan_pwr_limit_arr_11abg = {
535 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
536 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
537 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
538 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
539 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
540 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
541 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
542 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
543 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
544 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
545 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
546 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
547 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
548 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
549 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
550 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
551 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
552 .pwr_limit_reference_11p = 0x64,
Victor Goldenshtein1d614662012-12-27 15:49:47 +0200553 .per_chan_bo_mode_11_abg = { 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00,
555 0x00, 0x00, 0x00, 0x00,
556 0x00 },
557 .per_chan_bo_mode_11_p = { 0x00, 0x00, 0x00, 0x00 },
Yair Shapirad88949b2012-11-27 08:44:43 +0200558 .per_chan_pwr_limit_arr_11p = { 0xff, 0xff, 0xff, 0xff,
559 0xff, 0xff, 0xff },
Ido Reis16ea4732012-04-23 16:49:19 +0300560 .psat = 0,
Arik Nemtsov17d97712012-05-29 12:44:12 +0300561 .external_pa_dc2dc = 0,
Yair Shapirad88949b2012-11-27 08:44:43 +0200562 .number_of_assembled_ant2_4 = 2,
Arik Nemtsov17d97712012-05-29 12:44:12 +0300563 .number_of_assembled_ant5 = 1,
Igal Chernobelsky50e4c902013-09-09 12:24:32 +0300564 .low_power_val = 0xff,
565 .med_power_val = 0xff,
566 .high_power_val = 0xff,
567 .low_power_val_2nd = 0xff,
568 .med_power_val_2nd = 0xff,
569 .high_power_val_2nd = 0xff,
Ido Reisec4f4b72012-11-27 08:44:42 +0200570 .tx_rf_margin = 1,
Luciano Coelho46a1d512012-05-10 12:13:12 +0300571 },
Kobi Le2f1e502014-12-29 08:24:06 +0200572 .ap_sleep = { /* disabled by default */
573 .idle_duty_cycle = 0,
574 .connected_duty_cycle = 0,
575 .max_stations_thresh = 0,
576 .idle_conn_thresh = 0,
577 },
Luciano Coelho46a1d512012-05-10 12:13:12 +0300578};
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +0300579
Luciano Coelho82b890c2012-05-10 12:13:09 +0300580static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
581 [PART_TOP_PRCM_ELP_SOC] = {
Eyal Reizerbd763482015-04-29 17:50:03 +0300582 .mem = { .start = 0x00A00000, .size = 0x00012000 },
Luciano Coelho82b890c2012-05-10 12:13:09 +0300583 .reg = { .start = 0x00807000, .size = 0x00005000 },
584 .mem2 = { .start = 0x00800000, .size = 0x0000B000 },
585 .mem3 = { .start = 0x00000000, .size = 0x00000000 },
586 },
587 [PART_DOWN] = {
588 .mem = { .start = 0x00000000, .size = 0x00014000 },
589 .reg = { .start = 0x00810000, .size = 0x0000BFFF },
590 .mem2 = { .start = 0x00000000, .size = 0x00000000 },
591 .mem3 = { .start = 0x00000000, .size = 0x00000000 },
592 },
593 [PART_BOOT] = {
594 .mem = { .start = 0x00700000, .size = 0x0000030c },
595 .reg = { .start = 0x00802000, .size = 0x00014578 },
596 .mem2 = { .start = 0x00B00404, .size = 0x00001000 },
597 .mem3 = { .start = 0x00C00000, .size = 0x00000400 },
598 },
599 [PART_WORK] = {
600 .mem = { .start = 0x00800000, .size = 0x000050FC },
601 .reg = { .start = 0x00B00404, .size = 0x00001000 },
602 .mem2 = { .start = 0x00C00000, .size = 0x00000400 },
603 .mem3 = { .start = 0x00000000, .size = 0x00000000 },
604 },
605 [PART_PHY_INIT] = {
Ido Reise3b8bbb2012-11-27 08:44:51 +0200606 .mem = { .start = WL18XX_PHY_INIT_MEM_ADDR,
607 .size = WL18XX_PHY_INIT_MEM_SIZE },
Luciano Coelho82b890c2012-05-10 12:13:09 +0300608 .reg = { .start = 0x00000000, .size = 0x00000000 },
609 .mem2 = { .start = 0x00000000, .size = 0x00000000 },
610 .mem3 = { .start = 0x00000000, .size = 0x00000000 },
611 },
612};
613
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +0300614static const int wl18xx_rtable[REG_TABLE_LEN] = {
615 [REG_ECPU_CONTROL] = WL18XX_REG_ECPU_CONTROL,
616 [REG_INTERRUPT_NO_CLEAR] = WL18XX_REG_INTERRUPT_NO_CLEAR,
617 [REG_INTERRUPT_ACK] = WL18XX_REG_INTERRUPT_ACK,
618 [REG_COMMAND_MAILBOX_PTR] = WL18XX_REG_COMMAND_MAILBOX_PTR,
619 [REG_EVENT_MAILBOX_PTR] = WL18XX_REG_EVENT_MAILBOX_PTR,
620 [REG_INTERRUPT_TRIG] = WL18XX_REG_INTERRUPT_TRIG_H,
621 [REG_INTERRUPT_MASK] = WL18XX_REG_INTERRUPT_MASK,
Arik Nemtsov1c351da2012-05-10 12:13:39 +0300622 [REG_PC_ON_RECOVERY] = WL18XX_SCR_PAD4,
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +0300623 [REG_CHIP_ID_B] = WL18XX_REG_CHIP_ID_B,
624 [REG_CMD_MBOX_ADDRESS] = WL18XX_CMD_MBOX_ADDRESS,
625
626 /* data access memory addresses, used with partition translation */
627 [REG_SLV_MEM_DATA] = WL18XX_SLV_MEM_DATA,
628 [REG_SLV_REG_DATA] = WL18XX_SLV_REG_DATA,
629
630 /* raw data access memory addresses */
631 [REG_RAW_FW_STATUS_ADDR] = WL18XX_FW_STATUS_ADDR,
632};
633
Victor Goldenshteinef47d322013-09-17 18:41:28 +0300634static const struct wl18xx_clk_cfg wl18xx_clk_table_coex[NUM_CLOCK_CONFIGS] = {
635 [CLOCK_CONFIG_16_2_M] = { 8, 121, 0, 0, false },
636 [CLOCK_CONFIG_16_368_M] = { 8, 120, 0, 0, false },
637 [CLOCK_CONFIG_16_8_M] = { 8, 117, 0, 0, false },
638 [CLOCK_CONFIG_19_2_M] = { 10, 128, 0, 0, false },
639 [CLOCK_CONFIG_26_M] = { 11, 104, 0, 0, false },
640 [CLOCK_CONFIG_32_736_M] = { 8, 120, 0, 0, false },
641 [CLOCK_CONFIG_33_6_M] = { 8, 117, 0, 0, false },
642 [CLOCK_CONFIG_38_468_M] = { 10, 128, 0, 0, false },
643 [CLOCK_CONFIG_52_M] = { 11, 104, 0, 0, false },
644};
645
Luciano Coelhobe652022012-05-10 12:13:41 +0300646static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
647 [CLOCK_CONFIG_16_2_M] = { 7, 104, 801, 4, true },
648 [CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true },
649 [CLOCK_CONFIG_16_8_M] = { 7, 100, 0, 0, false },
650 [CLOCK_CONFIG_19_2_M] = { 8, 100, 0, 0, false },
651 [CLOCK_CONFIG_26_M] = { 13, 120, 0, 0, false },
652 [CLOCK_CONFIG_32_736_M] = { 9, 132, 3751, 4, true },
653 [CLOCK_CONFIG_33_6_M] = { 7, 100, 0, 0, false },
654 [CLOCK_CONFIG_38_468_M] = { 8, 100, 0, 0, false },
655 [CLOCK_CONFIG_52_M] = { 13, 120, 0, 0, false },
656};
657
Luciano Coelho0cd65432012-05-10 12:13:11 +0300658/* TODO: maybe move to a new header file? */
Eliad Peller750e9d12014-12-29 08:24:07 +0200659#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-4.bin"
Luciano Coelho0cd65432012-05-10 12:13:11 +0300660
661static int wl18xx_identify_chip(struct wl1271 *wl)
662{
663 int ret = 0;
664
665 switch (wl->chip.id) {
Ido Reis73395a792012-04-22 20:45:52 +0300666 case CHIP_ID_185x_PG20:
667 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG20)",
668 wl->chip.id);
669 wl->sr_fw_name = WL18XX_FW_NAME;
670 /* wl18xx uses the same firmware for PLT */
671 wl->plt_fw_name = WL18XX_FW_NAME;
Eliad Peller2718bf42012-11-27 08:44:47 +0200672 wl->quirks |= WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
Arik Nemtsovbf7c46a2012-06-11 10:41:08 +0300673 WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
Victor Goldenshtein01b3c0e2012-06-14 09:47:40 +0300674 WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
Eliad Peller78e28062012-11-22 18:06:15 +0200675 WLCORE_QUIRK_TX_PAD_LAST_FRAME |
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +0200676 WLCORE_QUIRK_REGDOMAIN_CONF |
Eliad Peller78e28062012-11-22 18:06:15 +0200677 WLCORE_QUIRK_DUAL_PROBE_TMPL;
Arik Nemtsov4a1ccce2012-06-25 17:46:40 +0300678
Luciano Coelho8675f9a2012-11-27 15:52:00 +0200679 wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER,
680 WL18XX_IFTYPE_VER, WL18XX_MAJOR_VER,
681 WL18XX_SUBTYPE_VER, WL18XX_MINOR_VER,
682 /* there's no separate multi-role FW */
683 0, 0, 0, 0);
Ido Reis73395a792012-04-22 20:45:52 +0300684 break;
Luciano Coelho0cd65432012-05-10 12:13:11 +0300685 case CHIP_ID_185x_PG10:
Luciano Coelhoe59bec12012-06-25 14:15:55 +0300686 wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
687 wl->chip.id);
688 ret = -ENODEV;
689 goto out;
Luciano Coelho0cd65432012-05-10 12:13:11 +0300690
Luciano Coelho0cd65432012-05-10 12:13:11 +0300691 default:
692 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
693 ret = -ENODEV;
694 goto out;
695 }
696
Igal Chernobelskyc83cb802013-09-09 12:24:38 +0300697 wl->fw_mem_block_size = 272;
698 wl->fwlog_end = 0x40000000;
699
Eliad Peller78e28062012-11-22 18:06:15 +0200700 wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
701 wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
702 wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
703 wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
Eliad Peller0a1c7202012-11-22 18:06:16 +0200704 wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
Igal Chernobelskyd21553f2013-03-12 17:19:35 +0200705 wl->ba_rx_session_count_max = WL18XX_RX_BA_MAX_SESSIONS;
Luciano Coelho0cd65432012-05-10 12:13:11 +0300706out:
707 return ret;
708}
709
Ido Yariv61343232012-06-18 15:50:21 +0300710static int wl18xx_set_clk(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300711{
Ido Yariv61343232012-06-18 15:50:21 +0300712 u16 clk_freq;
713 int ret;
Luciano Coelhod5b59272012-05-10 12:13:38 +0300714
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300715 ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
716 if (ret < 0)
717 goto out;
Luciano Coelhobe652022012-05-10 12:13:41 +0300718
719 /* TODO: PG2: apparently we need to read the clk type */
720
Ido Yariv61343232012-06-18 15:50:21 +0300721 ret = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT, &clk_freq);
722 if (ret < 0)
723 goto out;
724
Luciano Coelhobe652022012-05-10 12:13:41 +0300725 wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq,
726 wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m,
727 wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q,
728 wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit");
729
Victor Goldenshteinef47d322013-09-17 18:41:28 +0300730 /* coex PLL configuration */
731 ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_N,
732 wl18xx_clk_table_coex[clk_freq].n);
733 if (ret < 0)
734 goto out;
735
736 ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_M,
737 wl18xx_clk_table_coex[clk_freq].m);
738 if (ret < 0)
739 goto out;
740
741 /* bypass the swallowing logic */
742 ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
743 PLLSH_COEX_PLL_SWALLOW_EN_VAL1);
744 if (ret < 0)
745 goto out;
746
Ido Yariv61343232012-06-18 15:50:21 +0300747 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
748 wl18xx_clk_table[clk_freq].n);
749 if (ret < 0)
750 goto out;
751
752 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M,
753 wl18xx_clk_table[clk_freq].m);
754 if (ret < 0)
755 goto out;
Luciano Coelhobe652022012-05-10 12:13:41 +0300756
757 if (wl18xx_clk_table[clk_freq].swallow) {
758 /* first the 16 lower bits */
Ido Yariv61343232012-06-18 15:50:21 +0300759 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1,
760 wl18xx_clk_table[clk_freq].q &
761 PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK);
762 if (ret < 0)
763 goto out;
764
Luciano Coelhobe652022012-05-10 12:13:41 +0300765 /* then the 16 higher bits, masked out */
Ido Yariv61343232012-06-18 15:50:21 +0300766 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2,
767 (wl18xx_clk_table[clk_freq].q >> 16) &
768 PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK);
769 if (ret < 0)
770 goto out;
Luciano Coelhobe652022012-05-10 12:13:41 +0300771
772 /* first the 16 lower bits */
Ido Yariv61343232012-06-18 15:50:21 +0300773 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1,
774 wl18xx_clk_table[clk_freq].p &
775 PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK);
776 if (ret < 0)
777 goto out;
778
Luciano Coelhobe652022012-05-10 12:13:41 +0300779 /* then the 16 higher bits, masked out */
Ido Yariv61343232012-06-18 15:50:21 +0300780 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2,
781 (wl18xx_clk_table[clk_freq].p >> 16) &
782 PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK);
Luciano Coelhobe652022012-05-10 12:13:41 +0300783 } else {
Ido Yariv61343232012-06-18 15:50:21 +0300784 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN,
785 PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
Luciano Coelhobe652022012-05-10 12:13:41 +0300786 }
Ido Yariv61343232012-06-18 15:50:21 +0300787
Victor Goldenshteinef47d322013-09-17 18:41:28 +0300788 /* choose WCS PLL */
789 ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_SEL,
790 PLLSH_WL_PLL_SEL_WCS_PLL);
791 if (ret < 0)
792 goto out;
793
794 /* enable both PLLs */
795 ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL1);
796 if (ret < 0)
797 goto out;
798
799 udelay(1000);
800
801 /* disable coex PLL */
802 ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL2);
803 if (ret < 0)
804 goto out;
805
806 /* reset the swallowing logic */
807 ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
808 PLLSH_COEX_PLL_SWALLOW_EN_VAL2);
809 if (ret < 0)
810 goto out;
811
Ido Yariv61343232012-06-18 15:50:21 +0300812out:
813 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300814}
815
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300816static int wl18xx_boot_soft_reset(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300817{
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300818 int ret;
819
Luciano Coelho46a1d512012-05-10 12:13:12 +0300820 /* disable Rx/Tx */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300821 ret = wlcore_write32(wl, WL18XX_ENABLE, 0x0);
822 if (ret < 0)
823 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300824
825 /* disable auto calibration on start*/
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300826 ret = wlcore_write32(wl, WL18XX_SPARE_A2, 0xffff);
827
828out:
829 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300830}
831
832static int wl18xx_pre_boot(struct wl1271 *wl)
833{
Ido Yariv61343232012-06-18 15:50:21 +0300834 int ret;
835
836 ret = wl18xx_set_clk(wl);
837 if (ret < 0)
838 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300839
840 /* Continue the ELP wake up sequence */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300841 ret = wlcore_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
842 if (ret < 0)
843 goto out;
844
Luciano Coelho46a1d512012-05-10 12:13:12 +0300845 udelay(500);
846
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300847 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
848 if (ret < 0)
849 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300850
851 /* Disable interrupts */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300852 ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
853 if (ret < 0)
854 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300855
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300856 ret = wl18xx_boot_soft_reset(wl);
Luciano Coelho46a1d512012-05-10 12:13:12 +0300857
Ido Yariv61343232012-06-18 15:50:21 +0300858out:
859 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300860}
861
Ido Yariv61343232012-06-18 15:50:21 +0300862static int wl18xx_pre_upload(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300863{
864 u32 tmp;
Ido Yariv61343232012-06-18 15:50:21 +0300865 int ret;
Eyal Reizerbd763482015-04-29 17:50:03 +0300866 u16 irq_invert;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300867
Ido Reise3b8bbb2012-11-27 08:44:51 +0200868 BUILD_BUG_ON(sizeof(struct wl18xx_mac_and_phy_params) >
869 WL18XX_PHY_INIT_MEM_SIZE);
870
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300871 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
872 if (ret < 0)
873 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300874
875 /* TODO: check if this is all needed */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300876 ret = wlcore_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND);
877 if (ret < 0)
878 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300879
Ido Yariv61343232012-06-18 15:50:21 +0300880 ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp);
881 if (ret < 0)
882 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300883
884 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
885
Ido Yariv61343232012-06-18 15:50:21 +0300886 ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp);
Ido Reise3b8bbb2012-11-27 08:44:51 +0200887 if (ret < 0)
888 goto out;
889
890 /*
891 * Workaround for FDSP code RAM corruption (needed for PG2.1
892 * and newer; for older chips it's a NOP). Change FDSP clock
893 * settings so that it's muxed to the ATGP clock instead of
894 * its own clock.
895 */
896
897 ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
898 if (ret < 0)
899 goto out;
900
901 /* disable FDSP clock */
902 ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
903 MEM_FDSP_CLK_120_DISABLE);
904 if (ret < 0)
905 goto out;
906
907 /* set ATPG clock toward FDSP Code RAM rather than its own clock */
908 ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
909 MEM_FDSP_CODERAM_FUNC_CLK_SEL);
910 if (ret < 0)
911 goto out;
912
913 /* re-enable FDSP clock */
914 ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
915 MEM_FDSP_CLK_120_ENABLE);
Eyal Reizerbd763482015-04-29 17:50:03 +0300916 if (ret < 0)
917 goto out;
918
919 ret = irq_get_trigger_type(wl->irq);
920 if ((ret == IRQ_TYPE_LEVEL_LOW) || (ret == IRQ_TYPE_EDGE_FALLING)) {
921 wl1271_info("using inverted interrupt logic: %d", ret);
922 ret = wlcore_set_partition(wl,
923 &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
924 if (ret < 0)
925 goto out;
926
927 ret = wl18xx_top_reg_read(wl, TOP_FN0_CCCR_REG_32, &irq_invert);
928 if (ret < 0)
929 goto out;
930
931 irq_invert |= BIT(1);
932 ret = wl18xx_top_reg_write(wl, TOP_FN0_CCCR_REG_32, irq_invert);
933 if (ret < 0)
934 goto out;
935
936 ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
937 }
Ido Yariv61343232012-06-18 15:50:21 +0300938
939out:
940 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300941}
942
Ido Yariveb96f842012-06-18 13:21:55 +0300943static int wl18xx_set_mac_and_phy(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300944{
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300945 struct wl18xx_priv *priv = wl->priv;
Arik Nemtsov45777c42012-07-05 17:30:58 +0300946 struct wl18xx_mac_and_phy_params *params;
Ido Yariveb96f842012-06-18 13:21:55 +0300947 int ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300948
Arik Nemtsov45777c42012-07-05 17:30:58 +0300949 params = kmemdup(&priv->conf.phy, sizeof(*params), GFP_KERNEL);
950 if (!params) {
951 ret = -ENOMEM;
952 goto out;
953 }
954
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300955 ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
956 if (ret < 0)
957 goto out;
958
Arik Nemtsov45777c42012-07-05 17:30:58 +0300959 ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, params,
960 sizeof(*params), false);
Ido Yariveb96f842012-06-18 13:21:55 +0300961
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300962out:
Arik Nemtsov45777c42012-07-05 17:30:58 +0300963 kfree(params);
Ido Yariveb96f842012-06-18 13:21:55 +0300964 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300965}
966
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300967static int wl18xx_enable_interrupts(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300968{
Ido Reisf5755fe2012-04-23 17:35:25 +0300969 u32 event_mask, intr_mask;
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300970 int ret;
Ido Reisf5755fe2012-04-23 17:35:25 +0300971
Luciano Coelhoe59bec12012-06-25 14:15:55 +0300972 event_mask = WL18XX_ACX_EVENTS_VECTOR;
973 intr_mask = WL18XX_INTR_MASK;
Ido Reisf5755fe2012-04-23 17:35:25 +0300974
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300975 ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask);
976 if (ret < 0)
977 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300978
979 wlcore_enable_interrupts(wl);
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300980
981 ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
982 WL1271_ACX_INTR_ALL & ~intr_mask);
Ido Yariva8311c82012-08-15 18:29:04 +0300983 if (ret < 0)
984 goto disable_interrupts;
985
986 return ret;
987
988disable_interrupts:
989 wlcore_disable_interrupts(wl);
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300990
991out:
992 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300993}
994
995static int wl18xx_boot(struct wl1271 *wl)
996{
997 int ret;
998
999 ret = wl18xx_pre_boot(wl);
1000 if (ret < 0)
1001 goto out;
1002
Ido Yariv61343232012-06-18 15:50:21 +03001003 ret = wl18xx_pre_upload(wl);
1004 if (ret < 0)
1005 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +03001006
1007 ret = wlcore_boot_upload_firmware(wl);
1008 if (ret < 0)
1009 goto out;
1010
Ido Yariveb96f842012-06-18 13:21:55 +03001011 ret = wl18xx_set_mac_and_phy(wl);
1012 if (ret < 0)
1013 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +03001014
Eliad Pellerc50a2822012-11-22 18:06:19 +02001015 wl->event_mask = BSS_LOSS_EVENT_ID |
1016 SCAN_COMPLETE_EVENT_ID |
Eliad Peller750e9d12014-12-29 08:24:07 +02001017 RADAR_DETECTED_EVENT_ID |
Eliad Pellerc50a2822012-11-22 18:06:19 +02001018 RSSI_SNR_TRIGGER_0_EVENT_ID |
1019 PERIODIC_SCAN_COMPLETE_EVENT_ID |
Eyal Shapira0b700782012-11-28 11:42:47 +02001020 PERIODIC_SCAN_REPORT_EVENT_ID |
Eliad Pellerc50a2822012-11-22 18:06:19 +02001021 DUMMY_PACKET_EVENT_ID |
1022 PEER_REMOVE_COMPLETE_EVENT_ID |
1023 BA_SESSION_RX_CONSTRAINT_EVENT_ID |
1024 REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
1025 INACTIVE_STA_EVENT_ID |
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +02001026 CHANNEL_SWITCH_COMPLETE_EVENT_ID |
Eliad Pellere93e15f2014-07-11 03:01:33 +03001027 DFS_CHANNELS_CONFIG_COMPLETE_EVENT |
1028 SMART_CONFIG_SYNC_EVENT_ID |
Machani, Yaniv6d5c8982015-07-30 22:38:19 +03001029 SMART_CONFIG_DECODE_EVENT_ID |
1030 TIME_SYNC_EVENT_ID;
Eliad Pellerc50a2822012-11-22 18:06:19 +02001031
Eliad Peller71e996b2013-09-09 12:24:34 +03001032 wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID;
1033
Luciano Coelho46a1d512012-05-10 12:13:12 +03001034 ret = wlcore_boot_run_firmware(wl);
1035 if (ret < 0)
1036 goto out;
1037
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001038 ret = wl18xx_enable_interrupts(wl);
Luciano Coelho46a1d512012-05-10 12:13:12 +03001039
1040out:
1041 return ret;
1042}
1043
Ido Yariveb96f842012-06-18 13:21:55 +03001044static int wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
Luciano Coelho274c66c2012-05-10 12:13:13 +03001045 void *buf, size_t len)
1046{
1047 struct wl18xx_priv *priv = wl->priv;
1048
1049 memcpy(priv->cmd_buf, buf, len);
1050 memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len);
1051
Ido Yariveb96f842012-06-18 13:21:55 +03001052 return wlcore_write(wl, cmd_box_addr, priv->cmd_buf,
1053 WL18XX_CMD_MAX_SIZE, false);
Luciano Coelho274c66c2012-05-10 12:13:13 +03001054}
1055
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001056static int wl18xx_ack_event(struct wl1271 *wl)
Luciano Coelho274c66c2012-05-10 12:13:13 +03001057{
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001058 return wlcore_write_reg(wl, REG_INTERRUPT_TRIG,
1059 WL18XX_INTR_TRIG_EVENT_ACK);
Luciano Coelho274c66c2012-05-10 12:13:13 +03001060}
1061
Arik Nemtsov624845b2012-05-10 12:13:17 +03001062static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
1063{
1064 u32 blk_size = WL18XX_TX_HW_BLOCK_SIZE;
1065 return (len + blk_size - 1) / blk_size + spare_blks;
1066}
1067
Arik Nemtsovfb0f2e42012-05-10 12:13:18 +03001068static void
1069wl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
1070 u32 blks, u32 spare_blks)
1071{
1072 desc->wl18xx_mem.total_mem_blocks = blks;
Arik Nemtsovfb0f2e42012-05-10 12:13:18 +03001073}
1074
Arik Nemtsovd2361c52012-05-10 12:13:19 +03001075static void
1076wl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
1077 struct sk_buff *skb)
1078{
1079 desc->length = cpu_to_le16(skb->len);
1080
Ido Reis9fccc822012-05-13 14:53:40 +03001081 /* if only the last frame is to be padded, we unset this bit on Tx */
1082 if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME)
1083 desc->wl18xx_mem.ctrl = WL18XX_TX_CTRL_NOT_PADDED;
1084 else
1085 desc->wl18xx_mem.ctrl = 0;
1086
Arik Nemtsovd2361c52012-05-10 12:13:19 +03001087 wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
1088 "len: %d life: %d mem: %d", desc->hlid,
1089 le16_to_cpu(desc->length),
1090 le16_to_cpu(desc->life_time),
1091 desc->wl18xx_mem.total_mem_blocks);
1092}
1093
Arik Nemtsov9c809f82012-05-10 12:13:23 +03001094static enum wl_rx_buf_align
1095wl18xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
1096{
1097 if (rx_desc & RX_BUF_PADDED_PAYLOAD)
1098 return WLCORE_RX_BUF_PADDED;
1099
1100 return WLCORE_RX_BUF_ALIGNED;
1101}
1102
Arik Nemtsov30e2dd72012-05-10 12:13:24 +03001103static u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
1104 u32 data_len)
1105{
1106 struct wl1271_rx_descriptor *desc = rx_data;
1107
1108 /* invalid packet */
1109 if (data_len < sizeof(*desc))
1110 return 0;
1111
1112 return data_len - sizeof(*desc);
1113}
Arik Nemtsov9c809f82012-05-10 12:13:23 +03001114
Arik Nemtsov872b3452012-05-10 12:13:25 +03001115static void wl18xx_tx_immediate_completion(struct wl1271 *wl)
1116{
1117 wl18xx_tx_immediate_complete(wl);
1118}
1119
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001120static int wl18xx_set_host_cfg_bitmap(struct wl1271 *wl, u32 extra_mem_blk)
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001121{
1122 int ret;
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001123 u32 sdio_align_size = 0;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001124 u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE |
1125 HOST_IF_CFG_ADD_RX_ALIGNMENT;
Arik Nemtsovf2baf072012-05-10 12:13:46 +03001126
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001127 /* Enable Tx SDIO padding */
1128 if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) {
1129 host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
1130 sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
1131 }
1132
1133 /* Enable Rx SDIO padding */
1134 if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) {
1135 host_cfg_bitmap |= HOST_IF_CFG_RX_PAD_TO_SDIO_BLK;
1136 sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
1137 }
1138
1139 ret = wl18xx_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap,
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001140 sdio_align_size, extra_mem_blk,
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001141 WL18XX_HOST_IF_LEN_SIZE_FIELD);
1142 if (ret < 0)
1143 return ret;
1144
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001145 return 0;
1146}
1147
1148static int wl18xx_hw_init(struct wl1271 *wl)
1149{
1150 int ret;
1151 struct wl18xx_priv *priv = wl->priv;
1152
1153 /* (re)init private structures. Relevant on recovery as well. */
1154 priv->last_fw_rls_idx = 0;
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001155 priv->extra_spare_key_count = 0;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001156
1157 /* set the default amount of spare blocks in the bitmap */
1158 ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
1159 if (ret < 0)
1160 return ret;
1161
Guy Mishold1c54092015-07-27 09:46:02 +03001162 /* set the dynamic fw traces bitmap */
1163 ret = wl18xx_acx_dynamic_fw_traces(wl);
1164 if (ret < 0)
1165 return ret;
1166
Luciano Coelho102165c2012-05-10 12:13:53 +03001167 if (checksum_param) {
1168 ret = wl18xx_acx_set_checksum_state(wl);
1169 if (ret != 0)
1170 return ret;
1171 }
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001172
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001173 return ret;
1174}
1175
Eliad Peller75fb4df2014-02-10 13:47:21 +02001176static void wl18xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
1177 struct wl_fw_status *fw_status)
1178{
1179 struct wl18xx_fw_status *int_fw_status = raw_fw_status;
1180
1181 fw_status->intr = le32_to_cpu(int_fw_status->intr);
1182 fw_status->fw_rx_counter = int_fw_status->fw_rx_counter;
1183 fw_status->drv_rx_counter = int_fw_status->drv_rx_counter;
1184 fw_status->tx_results_counter = int_fw_status->tx_results_counter;
1185 fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs;
1186
1187 fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime);
1188 fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap);
1189 fw_status->link_fast_bitmap =
1190 le32_to_cpu(int_fw_status->link_fast_bitmap);
1191 fw_status->total_released_blks =
1192 le32_to_cpu(int_fw_status->total_released_blks);
1193 fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total);
1194
1195 fw_status->counters.tx_released_pkts =
1196 int_fw_status->counters.tx_released_pkts;
1197 fw_status->counters.tx_lnk_free_pkts =
1198 int_fw_status->counters.tx_lnk_free_pkts;
1199 fw_status->counters.tx_voice_released_blks =
1200 int_fw_status->counters.tx_voice_released_blks;
1201 fw_status->counters.tx_last_rate =
1202 int_fw_status->counters.tx_last_rate;
1203
1204 fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
1205
1206 fw_status->priv = &int_fw_status->priv;
1207}
1208
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001209static void wl18xx_set_tx_desc_csum(struct wl1271 *wl,
1210 struct wl1271_tx_hw_descr *desc,
1211 struct sk_buff *skb)
1212{
1213 u32 ip_hdr_offset;
1214 struct iphdr *ip_hdr;
1215
Luciano Coelho102165c2012-05-10 12:13:53 +03001216 if (!checksum_param) {
1217 desc->wl18xx_checksum_data = 0;
1218 return;
1219 }
1220
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001221 if (skb->ip_summed != CHECKSUM_PARTIAL) {
1222 desc->wl18xx_checksum_data = 0;
1223 return;
1224 }
1225
1226 ip_hdr_offset = skb_network_header(skb) - skb_mac_header(skb);
1227 if (WARN_ON(ip_hdr_offset >= (1<<7))) {
1228 desc->wl18xx_checksum_data = 0;
1229 return;
1230 }
1231
1232 desc->wl18xx_checksum_data = ip_hdr_offset << 1;
1233
1234 /* FW is interested only in the LSB of the protocol TCP=0 UDP=1 */
1235 ip_hdr = (void *)skb_network_header(skb);
1236 desc->wl18xx_checksum_data |= (ip_hdr->protocol & 0x01);
1237}
1238
Arik Nemtsov169da042012-05-10 12:13:28 +03001239static void wl18xx_set_rx_csum(struct wl1271 *wl,
1240 struct wl1271_rx_descriptor *desc,
1241 struct sk_buff *skb)
1242{
1243 if (desc->status & WL18XX_RX_CHECKSUM_MASK)
1244 skb->ip_summed = CHECKSUM_UNNECESSARY;
1245}
1246
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001247static bool wl18xx_is_mimo_supported(struct wl1271 *wl)
1248{
1249 struct wl18xx_priv *priv = wl->priv;
1250
Arik Nemtsovc80daad2012-11-28 11:42:46 +02001251 /* only support MIMO with multiple antennas, and when SISO
1252 * is not forced through config
1253 */
1254 return (priv->conf.phy.number_of_assembled_ant2_4 >= 2) &&
1255 (priv->conf.ht.mode != HT_MODE_WIDE) &&
1256 (priv->conf.ht.mode != HT_MODE_SISO20);
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001257}
1258
Luciano Coelho7ae25da2012-05-10 12:14:03 +03001259/*
1260 * TODO: instead of having these two functions to get the rate mask,
1261 * we should modify the wlvif->rate_set instead
1262 */
Arik Nemtsovf13af342012-05-10 12:13:32 +03001263static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl,
1264 struct wl12xx_vif *wlvif)
1265{
1266 u32 hw_rate_set = wlvif->rate_set;
1267
1268 if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
1269 wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
1270 wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
1271 hw_rate_set |= CONF_TX_RATE_USE_WIDE_CHAN;
1272
1273 /* we don't support MIMO in wide-channel mode */
1274 hw_rate_set &= ~CONF_TX_MIMO_RATES;
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001275 } else if (wl18xx_is_mimo_supported(wl)) {
1276 wl1271_debug(DEBUG_ACX, "using MIMO channel rate mask");
1277 hw_rate_set |= CONF_TX_MIMO_RATES;
Arik Nemtsovf13af342012-05-10 12:13:32 +03001278 }
1279
1280 return hw_rate_set;
1281}
1282
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001283static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
1284 struct wl12xx_vif *wlvif)
1285{
Arik Nemtsov0344dcd2012-07-05 15:23:02 +03001286 if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
1287 wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
1288 wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
1289
1290 /* sanity check - we don't support this */
1291 if (WARN_ON(wlvif->band != IEEE80211_BAND_5GHZ))
1292 return 0;
1293
1294 return CONF_TX_RATE_USE_WIDE_CHAN;
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001295 } else if (wl18xx_is_mimo_supported(wl) &&
Arik Nemtsov0344dcd2012-07-05 15:23:02 +03001296 wlvif->band == IEEE80211_BAND_2GHZ) {
1297 wl1271_debug(DEBUG_ACX, "using MIMO rate mask");
1298 /*
1299 * we don't care about HT channel here - if a peer doesn't
1300 * support MIMO, we won't enable it in its rates
1301 */
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001302 return CONF_TX_MIMO_RATES;
Luciano Coelho174a7302012-05-10 12:14:13 +03001303 } else {
1304 return 0;
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001305 }
1306}
1307
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001308static const char *wl18xx_rdl_name(enum wl18xx_rdl_num rdl_num)
1309{
1310 switch (rdl_num) {
1311 case RDL_1_HP:
1312 return "183xH";
1313 case RDL_2_SP:
1314 return "183x or 180x";
1315 case RDL_3_HP:
1316 return "187xH";
1317 case RDL_4_SP:
1318 return "187x";
1319 case RDL_5_SP:
1320 return "RDL11 - Not Supported";
1321 case RDL_6_SP:
1322 return "180xD";
1323 case RDL_7_SP:
1324 return "RDL13 - Not Supported (1893Q)";
1325 case RDL_8_SP:
1326 return "18xxQ";
1327 case RDL_NONE:
1328 return "UNTRIMMED";
1329 default:
1330 return "UNKNOWN";
1331 }
1332}
1333
Ido Yariv61343232012-06-18 15:50:21 +03001334static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
Arik Nemtsov54956292012-05-10 12:13:44 +03001335{
1336 u32 fuse;
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001337 s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0, package_type = 0;
Ido Yariv61343232012-06-18 15:50:21 +03001338 int ret;
Arik Nemtsov54956292012-05-10 12:13:44 +03001339
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001340 ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
1341 if (ret < 0)
1342 goto out;
Arik Nemtsov54956292012-05-10 12:13:44 +03001343
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001344 ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
1345 if (ret < 0)
1346 goto out;
1347
1348 package_type = (fuse >> WL18XX_PACKAGE_TYPE_OFFSET) & 1;
1349
Ido Yariv61343232012-06-18 15:50:21 +03001350 ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
1351 if (ret < 0)
1352 goto out;
1353
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001354 pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
1355 rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
1356
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001357 if ((rom <= 0xE) && (package_type == WL18XX_PACKAGE_TYPE_WSP))
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001358 metal = (fuse & WL18XX_METAL_VER_MASK) >>
1359 WL18XX_METAL_VER_OFFSET;
1360 else
1361 metal = (fuse & WL18XX_NEW_METAL_VER_MASK) >>
1362 WL18XX_NEW_METAL_VER_OFFSET;
1363
1364 ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
1365 if (ret < 0)
1366 goto out;
1367
1368 rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET;
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001369
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001370 wl1271_info("wl18xx HW: %s, PG %d.%d (ROM 0x%x)",
1371 wl18xx_rdl_name(rdl_ver), pg_ver, metal, rom);
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001372
Ido Yariv61343232012-06-18 15:50:21 +03001373 if (ver)
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001374 *ver = pg_ver;
Arik Nemtsov54956292012-05-10 12:13:44 +03001375
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001376 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
Arik Nemtsov54956292012-05-10 12:13:44 +03001377
Ido Yariv61343232012-06-18 15:50:21 +03001378out:
1379 return ret;
Arik Nemtsov54956292012-05-10 12:13:44 +03001380}
1381
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001382#define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin"
Eliad Peller6f157ed2015-05-06 11:29:54 +03001383
1384static int wl18xx_load_conf_file(struct device *dev, struct wlcore_conf *conf,
1385 struct wl18xx_priv_conf *priv_conf)
Luciano Coelho23ee9bf2012-05-10 12:13:29 +03001386{
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001387 struct wlcore_conf_file *conf_file;
1388 const struct firmware *fw;
1389 int ret;
1390
1391 ret = request_firmware(&fw, WL18XX_CONF_FILE_NAME, dev);
1392 if (ret < 0) {
1393 wl1271_error("could not get configuration binary %s: %d",
1394 WL18XX_CONF_FILE_NAME, ret);
Eliad Peller6f157ed2015-05-06 11:29:54 +03001395 return ret;
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001396 }
1397
1398 if (fw->size != WL18XX_CONF_SIZE) {
Luciano Coelho41844072012-06-21 15:33:10 +03001399 wl1271_error("configuration binary file size is wrong, expected %zu got %zu",
1400 WL18XX_CONF_SIZE, fw->size);
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001401 ret = -EINVAL;
Eliad Peller6f157ed2015-05-06 11:29:54 +03001402 goto out_release;
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001403 }
1404
1405 conf_file = (struct wlcore_conf_file *) fw->data;
1406
1407 if (conf_file->header.magic != cpu_to_le32(WL18XX_CONF_MAGIC)) {
1408 wl1271_error("configuration binary file magic number mismatch, "
1409 "expected 0x%0x got 0x%0x", WL18XX_CONF_MAGIC,
1410 conf_file->header.magic);
1411 ret = -EINVAL;
Eliad Peller6f157ed2015-05-06 11:29:54 +03001412 goto out_release;
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001413 }
1414
1415 if (conf_file->header.version != cpu_to_le32(WL18XX_CONF_VERSION)) {
1416 wl1271_error("configuration binary file version not supported, "
1417 "expected 0x%08x got 0x%08x",
1418 WL18XX_CONF_VERSION, conf_file->header.version);
1419 ret = -EINVAL;
Eliad Peller6f157ed2015-05-06 11:29:54 +03001420 goto out_release;
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001421 }
1422
Eliad Peller6f157ed2015-05-06 11:29:54 +03001423 memcpy(conf, &conf_file->core, sizeof(*conf));
1424 memcpy(priv_conf, &conf_file->priv, sizeof(*priv_conf));
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001425
Eliad Peller6f157ed2015-05-06 11:29:54 +03001426out_release:
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001427 release_firmware(fw);
1428 return ret;
Luciano Coelho23ee9bf2012-05-10 12:13:29 +03001429}
1430
Eliad Peller6f157ed2015-05-06 11:29:54 +03001431static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
1432{
1433 struct wl18xx_priv *priv = wl->priv;
1434
1435 if (wl18xx_load_conf_file(dev, &wl->conf, &priv->conf) < 0) {
1436 wl1271_warning("falling back to default config");
1437
1438 /* apply driver default configuration */
1439 memcpy(&wl->conf, &wl18xx_conf, sizeof(wl->conf));
1440 /* apply default private configuration */
1441 memcpy(&priv->conf, &wl18xx_default_priv_conf,
1442 sizeof(priv->conf));
1443 }
1444
1445 return 0;
1446}
1447
Luciano Coelhobe42aee2012-05-10 12:13:50 +03001448static int wl18xx_plt_init(struct wl1271 *wl)
1449{
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001450 int ret;
1451
Yair Shapira16bc10c32012-07-11 18:48:05 +03001452 /* calibrator based auto/fem detect not supported for 18xx */
1453 if (wl->plt_mode == PLT_FEM_DETECT) {
1454 wl1271_error("wl18xx_plt_init: PLT FEM_DETECT not supported");
1455 return -EINVAL;
1456 }
1457
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001458 ret = wlcore_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT);
1459 if (ret < 0)
1460 return ret;
Luciano Coelhobe42aee2012-05-10 12:13:50 +03001461
1462 return wl->ops->boot(wl);
1463}
1464
Ido Yariv61343232012-06-18 15:50:21 +03001465static int wl18xx_get_mac(struct wl1271 *wl)
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001466{
1467 u32 mac1, mac2;
Ido Yariv61343232012-06-18 15:50:21 +03001468 int ret;
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001469
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001470 ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
1471 if (ret < 0)
1472 goto out;
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001473
Ido Yariv61343232012-06-18 15:50:21 +03001474 ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1, &mac1);
1475 if (ret < 0)
1476 goto out;
1477
1478 ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2, &mac2);
1479 if (ret < 0)
1480 goto out;
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001481
1482 /* these are the two parts of the BD_ADDR */
1483 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
1484 ((mac1 & 0xff000000) >> 24);
1485 wl->fuse_nic_addr = (mac1 & 0xffffff);
1486
Luciano Coelhobc2ab3b2013-05-08 12:54:56 +03001487 if (!wl->fuse_oui_addr && !wl->fuse_nic_addr) {
1488 u8 mac[ETH_ALEN];
1489
1490 eth_random_addr(mac);
1491
1492 wl->fuse_oui_addr = (mac[0] << 16) + (mac[1] << 8) + mac[2];
1493 wl->fuse_nic_addr = (mac[3] << 16) + (mac[4] << 8) + mac[5];
1494 wl1271_warning("MAC address from fuse not available, using random locally administered addresses.");
1495 }
1496
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001497 ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
Ido Yariv61343232012-06-18 15:50:21 +03001498
1499out:
1500 return ret;
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001501}
1502
Luciano Coelho283e8c42012-05-10 12:14:11 +03001503static int wl18xx_handle_static_data(struct wl1271 *wl,
1504 struct wl1271_static_data *static_data)
1505{
1506 struct wl18xx_static_data_priv *static_data_priv =
1507 (struct wl18xx_static_data_priv *) static_data->priv;
1508
Yair Shapira1defbeb2012-08-07 17:38:21 +03001509 strncpy(wl->chip.phy_fw_ver_str, static_data_priv->phy_version,
1510 sizeof(wl->chip.phy_fw_ver_str));
1511
1512 /* make sure the string is NULL-terminated */
1513 wl->chip.phy_fw_ver_str[sizeof(wl->chip.phy_fw_ver_str) - 1] = '\0';
1514
Luciano Coelho283e8c42012-05-10 12:14:11 +03001515 wl1271_info("PHY firmware version: %s", static_data_priv->phy_version);
1516
1517 return 0;
1518}
1519
Arik Nemtsov32bb2c02012-05-18 07:46:37 +03001520static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
1521{
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001522 struct wl18xx_priv *priv = wl->priv;
1523
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001524 /* If we have keys requiring extra spare, indulge them */
1525 if (priv->extra_spare_key_count)
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001526 return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
1527
1528 return WL18XX_TX_HW_BLOCK_SPARE;
1529}
1530
1531static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
1532 struct ieee80211_vif *vif,
1533 struct ieee80211_sta *sta,
1534 struct ieee80211_key_conf *key_conf)
1535{
1536 struct wl18xx_priv *priv = wl->priv;
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001537 bool change_spare = false, special_enc;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001538 int ret;
1539
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001540 wl1271_debug(DEBUG_CRYPT, "extra spare keys before: %d",
1541 priv->extra_spare_key_count);
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001542
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001543 special_enc = key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
1544 key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001545
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001546 ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
1547 if (ret < 0)
1548 goto out;
1549
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001550 /*
1551 * when adding the first or removing the last GEM/TKIP key,
1552 * we have to adjust the number of spare blocks.
1553 */
1554 if (special_enc) {
1555 if (cmd == SET_KEY) {
1556 /* first key */
1557 change_spare = (priv->extra_spare_key_count == 0);
1558 priv->extra_spare_key_count++;
1559 } else if (cmd == DISABLE_KEY) {
1560 /* last key */
1561 change_spare = (priv->extra_spare_key_count == 1);
1562 priv->extra_spare_key_count--;
1563 }
1564 }
1565
1566 wl1271_debug(DEBUG_CRYPT, "extra spare keys after: %d",
1567 priv->extra_spare_key_count);
1568
1569 if (!change_spare)
1570 goto out;
1571
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001572 /* key is now set, change the spare blocks */
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001573 if (priv->extra_spare_key_count)
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001574 ret = wl18xx_set_host_cfg_bitmap(wl,
1575 WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001576 else
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001577 ret = wl18xx_set_host_cfg_bitmap(wl,
1578 WL18XX_TX_HW_BLOCK_SPARE);
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001579
1580out:
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001581 return ret;
Arik Nemtsov32bb2c02012-05-18 07:46:37 +03001582}
1583
Ido Reis9fccc822012-05-13 14:53:40 +03001584static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
1585 u32 buf_offset, u32 last_len)
1586{
1587 if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) {
1588 struct wl1271_tx_hw_descr *last_desc;
1589
1590 /* get the last TX HW descriptor written to the aggr buf */
1591 last_desc = (struct wl1271_tx_hw_descr *)(wl->aggr_buf +
1592 buf_offset - last_len);
1593
1594 /* the last frame is padded up to an SDIO block */
1595 last_desc->wl18xx_mem.ctrl &= ~WL18XX_TX_CTRL_NOT_PADDED;
1596 return ALIGN(buf_offset, WL12XX_BUS_BLOCK_SIZE);
1597 }
1598
1599 /* no modifications */
1600 return buf_offset;
1601}
1602
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001603static void wl18xx_sta_rc_update(struct wl1271 *wl,
Eliad Peller7d3b29e2014-12-29 08:24:03 +02001604 struct wl12xx_vif *wlvif)
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001605{
Eliad Peller7d3b29e2014-12-29 08:24:03 +02001606 bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40;
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001607
1608 wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
1609
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001610 /* sanity */
1611 if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
Eliad Peller7d3b29e2014-12-29 08:24:03 +02001612 return;
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001613
1614 /* ignore the change before association */
1615 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller7d3b29e2014-12-29 08:24:03 +02001616 return;
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001617
1618 /*
1619 * If we started out as wide, we can change the operation mode. If we
1620 * thought this was a 20mhz AP, we have to reconnect
1621 */
1622 if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS ||
1623 wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS)
1624 wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
1625 else
1626 ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001627}
1628
Eliad Peller530abe12012-11-28 11:42:31 +02001629static int wl18xx_set_peer_cap(struct wl1271 *wl,
1630 struct ieee80211_sta_ht_cap *ht_cap,
1631 bool allow_ht_operation,
1632 u32 rate_set, u8 hlid)
1633{
1634 return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation,
1635 rate_set, hlid);
1636}
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001637
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001638static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
1639 struct wl1271_link *lnk)
1640{
1641 u8 thold;
1642 struct wl18xx_fw_status_priv *status_priv =
Eliad Peller75fb4df2014-02-10 13:47:21 +02001643 (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001644 unsigned long suspend_bitmap;
Eliad Peller9bccb8a2014-07-11 03:01:38 +03001645
1646 /* if we don't have the link map yet, assume they all low prio */
1647 if (!status_priv)
1648 return false;
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001649
1650 /* suspended links are never high priority */
Eliad Peller9bccb8a2014-07-11 03:01:38 +03001651 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001652 if (test_bit(hlid, &suspend_bitmap))
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001653 return false;
1654
1655 /* the priority thresholds are taken from FW */
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001656 if (test_bit(hlid, &wl->fw_fast_lnk_map) &&
1657 !test_bit(hlid, &wl->ap_fw_ps_map))
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001658 thold = status_priv->tx_fast_link_prio_threshold;
1659 else
1660 thold = status_priv->tx_slow_link_prio_threshold;
1661
1662 return lnk->allocated_pkts < thold;
1663}
1664
1665static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
1666 struct wl1271_link *lnk)
1667{
1668 u8 thold;
1669 struct wl18xx_fw_status_priv *status_priv =
Eliad Peller75fb4df2014-02-10 13:47:21 +02001670 (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001671 unsigned long suspend_bitmap;
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001672
Eliad Peller9bccb8a2014-07-11 03:01:38 +03001673 /* if we don't have the link map yet, assume they all low prio */
1674 if (!status_priv)
1675 return true;
1676
1677 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001678 if (test_bit(hlid, &suspend_bitmap))
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001679 thold = status_priv->tx_suspend_threshold;
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001680 else if (test_bit(hlid, &wl->fw_fast_lnk_map) &&
1681 !test_bit(hlid, &wl->ap_fw_ps_map))
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001682 thold = status_priv->tx_fast_stop_threshold;
1683 else
1684 thold = status_priv->tx_slow_stop_threshold;
1685
1686 return lnk->allocated_pkts < thold;
1687}
1688
Igal Chernobelskyc83cb802013-09-09 12:24:38 +03001689static u32 wl18xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
1690{
1691 return hwaddr & ~0x80000000;
1692}
1693
Ido Yariv3992eb22012-09-02 12:29:27 +03001694static int wl18xx_setup(struct wl1271 *wl);
1695
Luciano Coelho0cd65432012-05-10 12:13:11 +03001696static struct wlcore_ops wl18xx_ops = {
Ido Yariv3992eb22012-09-02 12:29:27 +03001697 .setup = wl18xx_setup,
Luciano Coelho46a1d512012-05-10 12:13:12 +03001698 .identify_chip = wl18xx_identify_chip,
1699 .boot = wl18xx_boot,
Luciano Coelhobe42aee2012-05-10 12:13:50 +03001700 .plt_init = wl18xx_plt_init,
Luciano Coelho274c66c2012-05-10 12:13:13 +03001701 .trigger_cmd = wl18xx_trigger_cmd,
1702 .ack_event = wl18xx_ack_event,
Eliad Pellerc50a2822012-11-22 18:06:19 +02001703 .wait_for_event = wl18xx_wait_for_event,
1704 .process_mailbox_events = wl18xx_process_mailbox_events,
Arik Nemtsov624845b2012-05-10 12:13:17 +03001705 .calc_tx_blocks = wl18xx_calc_tx_blocks,
Arik Nemtsovfb0f2e42012-05-10 12:13:18 +03001706 .set_tx_desc_blocks = wl18xx_set_tx_desc_blocks,
Arik Nemtsovd2361c52012-05-10 12:13:19 +03001707 .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len,
Arik Nemtsov9c809f82012-05-10 12:13:23 +03001708 .get_rx_buf_align = wl18xx_get_rx_buf_align,
Arik Nemtsov30e2dd72012-05-10 12:13:24 +03001709 .get_rx_packet_len = wl18xx_get_rx_packet_len,
Arik Nemtsov872b3452012-05-10 12:13:25 +03001710 .tx_immediate_compl = wl18xx_tx_immediate_completion,
1711 .tx_delayed_compl = NULL,
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001712 .hw_init = wl18xx_hw_init,
Eliad Peller75fb4df2014-02-10 13:47:21 +02001713 .convert_fw_status = wl18xx_convert_fw_status,
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001714 .set_tx_desc_csum = wl18xx_set_tx_desc_csum,
Arik Nemtsov54956292012-05-10 12:13:44 +03001715 .get_pg_ver = wl18xx_get_pg_ver,
Arik Nemtsov169da042012-05-10 12:13:28 +03001716 .set_rx_csum = wl18xx_set_rx_csum,
Arik Nemtsovf13af342012-05-10 12:13:32 +03001717 .sta_get_ap_rate_mask = wl18xx_sta_get_ap_rate_mask,
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001718 .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001719 .get_mac = wl18xx_get_mac,
Luciano Coelhoad62d812012-05-10 12:14:19 +03001720 .debugfs_init = wl18xx_debugfs_add_files,
Eliad Peller78e28062012-11-22 18:06:15 +02001721 .scan_start = wl18xx_scan_start,
1722 .scan_stop = wl18xx_scan_stop,
Eliad Peller78e28062012-11-22 18:06:15 +02001723 .sched_scan_start = wl18xx_sched_scan_start,
1724 .sched_scan_stop = wl18xx_scan_sched_scan_stop,
Luciano Coelho283e8c42012-05-10 12:14:11 +03001725 .handle_static_data = wl18xx_handle_static_data,
Arik Nemtsov32bb2c02012-05-18 07:46:37 +03001726 .get_spare_blocks = wl18xx_get_spare_blocks,
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001727 .set_key = wl18xx_set_key,
Eliad Pellerfcab1892012-11-22 18:06:18 +02001728 .channel_switch = wl18xx_cmd_channel_switch,
Ido Reis9fccc822012-05-13 14:53:40 +03001729 .pre_pkt_send = wl18xx_pre_pkt_send,
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001730 .sta_rc_update = wl18xx_sta_rc_update,
Eliad Peller530abe12012-11-28 11:42:31 +02001731 .set_peer_cap = wl18xx_set_peer_cap,
Igal Chernobelskyc83cb802013-09-09 12:24:38 +03001732 .convert_hwaddr = wl18xx_convert_hwaddr,
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001733 .lnk_high_prio = wl18xx_lnk_high_prio,
1734 .lnk_low_prio = wl18xx_lnk_low_prio,
Eliad Pellerccb1df92014-07-11 03:01:31 +03001735 .smart_config_start = wl18xx_cmd_smart_config_start,
1736 .smart_config_stop = wl18xx_cmd_smart_config_stop,
1737 .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
Ram Amrani6d5a7482014-12-29 08:24:04 +02001738 .interrupt_notify = wl18xx_acx_interrupt_notify_config,
1739 .rx_ba_filter = wl18xx_acx_rx_ba_filter,
Kobi Le2f1e502014-12-29 08:24:06 +02001740 .ap_sleep = wl18xx_acx_ap_sleep,
Eliad Peller750e9d12014-12-29 08:24:07 +02001741 .set_cac = wl18xx_cmd_set_cac,
Eliad Peller830513a2014-12-29 08:24:10 +02001742 .dfs_master_restart = wl18xx_cmd_dfs_master_restart,
Luciano Coelho0cd65432012-05-10 12:13:11 +03001743};
1744
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001745/* HT cap appropriate for wide channels in 2Ghz */
1746static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
Arik Nemtsov0e0f5a32012-05-10 12:13:35 +03001747 .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
Eliad Peller0330ee12012-11-27 08:44:49 +02001748 IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40 |
1749 IEEE80211_HT_CAP_GRN_FLD,
Arik Nemtsov0e0f5a32012-05-10 12:13:35 +03001750 .ht_supported = true,
1751 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
1752 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
1753 .mcs = {
1754 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
1755 .rx_highest = cpu_to_le16(150),
1756 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1757 },
1758};
1759
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001760/* HT cap appropriate for wide channels in 5Ghz */
1761static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
1762 .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
Eliad Peller0330ee12012-11-27 08:44:49 +02001763 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
1764 IEEE80211_HT_CAP_GRN_FLD,
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001765 .ht_supported = true,
1766 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
1767 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
1768 .mcs = {
1769 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
1770 .rx_highest = cpu_to_le16(150),
1771 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1772 },
1773};
1774
Luciano Coelho83342712012-05-10 12:14:15 +03001775/* HT cap appropriate for SISO 20 */
1776static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
Eliad Peller0330ee12012-11-27 08:44:49 +02001777 .cap = IEEE80211_HT_CAP_SGI_20 |
1778 IEEE80211_HT_CAP_GRN_FLD,
Luciano Coelho83342712012-05-10 12:14:15 +03001779 .ht_supported = true,
1780 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
1781 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
1782 .mcs = {
1783 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
1784 .rx_highest = cpu_to_le16(72),
1785 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1786 },
1787};
1788
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +03001789/* HT cap appropriate for MIMO rates in 20mhz channel */
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03001790static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
Eliad Peller0330ee12012-11-27 08:44:49 +02001791 .cap = IEEE80211_HT_CAP_SGI_20 |
1792 IEEE80211_HT_CAP_GRN_FLD,
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +03001793 .ht_supported = true,
1794 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
1795 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
1796 .mcs = {
1797 .rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, },
1798 .rx_highest = cpu_to_le16(144),
1799 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1800 },
1801};
1802
Eliad Pellerabf0b242014-02-10 13:47:24 +02001803static const struct ieee80211_iface_limit wl18xx_iface_limits[] = {
1804 {
1805 .max = 3,
1806 .types = BIT(NL80211_IFTYPE_STATION),
1807 },
1808 {
1809 .max = 1,
1810 .types = BIT(NL80211_IFTYPE_AP) |
1811 BIT(NL80211_IFTYPE_P2P_GO) |
1812 BIT(NL80211_IFTYPE_P2P_CLIENT),
1813 },
1814};
1815
1816static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {
1817 {
1818 .max = 2,
1819 .types = BIT(NL80211_IFTYPE_AP),
1820 },
1821};
1822
1823static const struct ieee80211_iface_combination
1824wl18xx_iface_combinations[] = {
1825 {
1826 .max_interfaces = 3,
1827 .limits = wl18xx_iface_limits,
1828 .n_limits = ARRAY_SIZE(wl18xx_iface_limits),
1829 .num_different_channels = 2,
1830 },
1831 {
1832 .max_interfaces = 2,
1833 .limits = wl18xx_iface_ap_limits,
1834 .n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits),
1835 .num_different_channels = 1,
Eliad Peller86f2db862014-12-29 08:24:13 +02001836 .radar_detect_widths = BIT(NL80211_CHAN_NO_HT) |
1837 BIT(NL80211_CHAN_HT20) |
1838 BIT(NL80211_CHAN_HT40MINUS) |
1839 BIT(NL80211_CHAN_HT40PLUS),
Eliad Pellerabf0b242014-02-10 13:47:24 +02001840 }
1841};
1842
Ido Yariv3992eb22012-09-02 12:29:27 +03001843static int wl18xx_setup(struct wl1271 *wl)
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001844{
Ido Yariv3992eb22012-09-02 12:29:27 +03001845 struct wl18xx_priv *priv = wl->priv;
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001846 int ret;
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001847
Eliad Pellerda08fdf2014-02-10 13:47:22 +02001848 BUILD_BUG_ON(WL18XX_MAX_LINKS > WLCORE_MAX_LINKS);
Eliad Peller32f0fd52014-02-10 13:47:23 +02001849 BUILD_BUG_ON(WL18XX_MAX_AP_STATIONS > WL18XX_MAX_LINKS);
Eliad Pellerda08fdf2014-02-10 13:47:22 +02001850
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +03001851 wl->rtable = wl18xx_rtable;
Igal Chernobelskyf1c434d2012-07-31 14:48:46 +03001852 wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
Yair Shapirac91ec5f2012-11-28 11:42:39 +02001853 wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
Eliad Pellerda08fdf2014-02-10 13:47:22 +02001854 wl->num_links = WL18XX_MAX_LINKS;
Eliad Peller32f0fd52014-02-10 13:47:23 +02001855 wl->max_ap_stations = WL18XX_MAX_AP_STATIONS;
Eliad Pellerabf0b242014-02-10 13:47:24 +02001856 wl->iface_combinations = wl18xx_iface_combinations;
1857 wl->n_iface_combinations = ARRAY_SIZE(wl18xx_iface_combinations);
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03001858 wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
Arik Nemtsovf648eab2012-05-10 12:13:20 +03001859 wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
1860 wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
1861 wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
Eliad Peller75fb4df2014-02-10 13:47:21 +02001862 wl->fw_status_len = sizeof(struct wl18xx_fw_status);
Arik Nemtsov1fab39d2012-05-10 12:13:21 +03001863 wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv);
Luciano Coelho8c0ea102012-05-10 12:14:09 +03001864 wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
Luciano Coelho283e8c42012-05-10 12:14:11 +03001865 wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
Luciano Coelho83342712012-05-10 12:14:15 +03001866
Arik Nemtsov09aad142012-06-10 22:57:30 +03001867 if (num_rx_desc_param != -1)
1868 wl->num_rx_desc = num_rx_desc_param;
1869
Ido Yariv3992eb22012-09-02 12:29:27 +03001870 ret = wl18xx_conf_init(wl, wl->dev);
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001871 if (ret < 0)
Ido Yariv3992eb22012-09-02 12:29:27 +03001872 return ret;
Luciano Coelho776f0302012-05-10 12:13:58 +03001873
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001874 /* If the module param is set, update it in conf */
1875 if (board_type_param) {
1876 if (!strcmp(board_type_param, "fpga")) {
1877 priv->conf.phy.board_type = BOARD_TYPE_FPGA_18XX;
1878 } else if (!strcmp(board_type_param, "hdk")) {
1879 priv->conf.phy.board_type = BOARD_TYPE_HDK_18XX;
1880 } else if (!strcmp(board_type_param, "dvp")) {
1881 priv->conf.phy.board_type = BOARD_TYPE_DVP_18XX;
1882 } else if (!strcmp(board_type_param, "evb")) {
1883 priv->conf.phy.board_type = BOARD_TYPE_EVB_18XX;
1884 } else if (!strcmp(board_type_param, "com8")) {
1885 priv->conf.phy.board_type = BOARD_TYPE_COM8_18XX;
1886 } else {
1887 wl1271_error("invalid board type '%s'",
1888 board_type_param);
Ido Yariv3992eb22012-09-02 12:29:27 +03001889 return -EINVAL;
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001890 }
1891 }
1892
Ido Reise1c497c2012-07-13 00:12:08 +03001893 if (priv->conf.phy.board_type >= NUM_BOARD_TYPES) {
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001894 wl1271_error("invalid board type '%d'",
1895 priv->conf.phy.board_type);
Ido Yariv3992eb22012-09-02 12:29:27 +03001896 return -EINVAL;
Luciano Coelhoa9c130d2012-05-10 12:13:37 +03001897 }
1898
Arik Nemtsov17d97712012-05-29 12:44:12 +03001899 if (low_band_component_param != -1)
1900 priv->conf.phy.low_band_component = low_band_component_param;
1901 if (low_band_component_type_param != -1)
Luciano Coelho858403a2012-05-10 12:14:17 +03001902 priv->conf.phy.low_band_component_type =
Arik Nemtsov17d97712012-05-29 12:44:12 +03001903 low_band_component_type_param;
1904 if (high_band_component_param != -1)
1905 priv->conf.phy.high_band_component = high_band_component_param;
1906 if (high_band_component_type_param != -1)
Luciano Coelho858403a2012-05-10 12:14:17 +03001907 priv->conf.phy.high_band_component_type =
Arik Nemtsov17d97712012-05-29 12:44:12 +03001908 high_band_component_type_param;
1909 if (pwr_limit_reference_11_abg_param != -1)
Luciano Coelho7b03c302012-05-10 12:14:18 +03001910 priv->conf.phy.pwr_limit_reference_11_abg =
Arik Nemtsov17d97712012-05-29 12:44:12 +03001911 pwr_limit_reference_11_abg_param;
1912 if (n_antennas_2_param != -1)
1913 priv->conf.phy.number_of_assembled_ant2_4 = n_antennas_2_param;
1914 if (n_antennas_5_param != -1)
1915 priv->conf.phy.number_of_assembled_ant5 = n_antennas_5_param;
1916 if (dc2dc_param != -1)
1917 priv->conf.phy.external_pa_dc2dc = dc2dc_param;
Luciano Coelho7b03c302012-05-10 12:14:18 +03001918
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001919 if (ht_mode_param) {
1920 if (!strcmp(ht_mode_param, "default"))
1921 priv->conf.ht.mode = HT_MODE_DEFAULT;
1922 else if (!strcmp(ht_mode_param, "wide"))
1923 priv->conf.ht.mode = HT_MODE_WIDE;
1924 else if (!strcmp(ht_mode_param, "siso20"))
1925 priv->conf.ht.mode = HT_MODE_SISO20;
1926 else {
1927 wl1271_error("invalid ht_mode '%s'", ht_mode_param);
Ido Yariv3992eb22012-09-02 12:29:27 +03001928 return -EINVAL;
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001929 }
1930 }
1931
1932 if (priv->conf.ht.mode == HT_MODE_DEFAULT) {
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001933 /*
1934 * Only support mimo with multiple antennas. Fall back to
Arik Nemtsov8c5dab12012-08-15 19:11:43 +03001935 * siso40.
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001936 */
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001937 if (wl18xx_is_mimo_supported(wl))
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001938 wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
1939 &wl18xx_mimo_ht_cap_2ghz);
1940 else
1941 wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
Arik Nemtsov8c5dab12012-08-15 19:11:43 +03001942 &wl18xx_siso40_ht_cap_2ghz);
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001943
1944 /* 5Ghz is always wide */
1945 wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001946 &wl18xx_siso40_ht_cap_5ghz);
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001947 } else if (priv->conf.ht.mode == HT_MODE_WIDE) {
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001948 wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001949 &wl18xx_siso40_ht_cap_2ghz);
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001950 wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001951 &wl18xx_siso40_ht_cap_5ghz);
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001952 } else if (priv->conf.ht.mode == HT_MODE_SISO20) {
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001953 wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
1954 &wl18xx_siso20_ht_cap);
1955 wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
1956 &wl18xx_siso20_ht_cap);
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001957 }
1958
Luciano Coelho102165c2012-05-10 12:13:53 +03001959 if (!checksum_param) {
1960 wl18xx_ops.set_rx_csum = NULL;
1961 wl18xx_ops.init_vif = NULL;
1962 }
1963
Yair Shapirae166de52012-08-05 16:51:16 +03001964 /* Enable 11a Band only if we have 5G antennas */
1965 wl->enable_11a = (priv->conf.phy.number_of_assembled_ant5 != 0);
Luciano Coelho1ddbc7d2012-05-10 12:13:56 +03001966
Ido Yariv3992eb22012-09-02 12:29:27 +03001967 return 0;
1968}
1969
Bill Pembertonb74324d2012-12-03 09:56:42 -05001970static int wl18xx_probe(struct platform_device *pdev)
Ido Yariv3992eb22012-09-02 12:29:27 +03001971{
1972 struct wl1271 *wl;
1973 struct ieee80211_hw *hw;
1974 int ret;
1975
1976 hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv),
Eliad Pellerc50a2822012-11-22 18:06:19 +02001977 WL18XX_AGGR_BUFFER_SIZE,
1978 sizeof(struct wl18xx_event_mailbox));
Ido Yariv3992eb22012-09-02 12:29:27 +03001979 if (IS_ERR(hw)) {
1980 wl1271_error("can't allocate hw");
1981 ret = PTR_ERR(hw);
1982 goto out;
1983 }
1984
1985 wl = hw->priv;
1986 wl->ops = &wl18xx_ops;
1987 wl->ptable = wl18xx_ptable;
1988 ret = wlcore_probe(wl, pdev);
1989 if (ret)
1990 goto out_free;
1991
1992 return ret;
Luciano Coelho83342712012-05-10 12:14:15 +03001993
1994out_free:
1995 wlcore_free_hw(wl);
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001996out:
1997 return ret;
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001998}
1999
Bill Pembertonb74324d2012-12-03 09:56:42 -05002000static const struct platform_device_id wl18xx_id_table[] = {
Luciano Coelho9a1a6992012-05-10 12:13:06 +03002001 { "wl18xx", 0 },
2002 { } /* Terminating Entry */
2003};
2004MODULE_DEVICE_TABLE(platform, wl18xx_id_table);
2005
2006static struct platform_driver wl18xx_driver = {
2007 .probe = wl18xx_probe,
Bill Pembertonb74324d2012-12-03 09:56:42 -05002008 .remove = wlcore_remove,
Luciano Coelho9a1a6992012-05-10 12:13:06 +03002009 .id_table = wl18xx_id_table,
2010 .driver = {
2011 .name = "wl18xx_driver",
Luciano Coelho9a1a6992012-05-10 12:13:06 +03002012 }
2013};
2014
Devendra Naga77e7b302012-08-29 23:03:01 +05302015module_platform_driver(wl18xx_driver);
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +03002016module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR);
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03002017MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20");
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +03002018
Luciano Coelhoa9c130d2012-05-10 12:13:37 +03002019module_param_named(board_type, board_type_param, charp, S_IRUSR);
Luciano Coelho4b9d2362012-05-10 12:13:59 +03002020MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
2021 "dvp");
Luciano Coelhoa9c130d2012-05-10 12:13:37 +03002022
Luciano Coelho102165c2012-05-10 12:13:53 +03002023module_param_named(checksum, checksum_param, bool, S_IRUSR);
Assaf Azulay3d62eb52012-05-10 12:14:23 +03002024MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)");
Luciano Coelho102165c2012-05-10 12:13:53 +03002025
Arik Nemtsov17d97712012-05-29 12:44:12 +03002026module_param_named(dc2dc, dc2dc_param, int, S_IRUSR);
2027MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)");
2028
2029module_param_named(n_antennas_2, n_antennas_2_param, int, S_IRUSR);
2030MODULE_PARM_DESC(n_antennas_2,
2031 "Number of installed 2.4GHz antennas: 1 (default) or 2");
2032
2033module_param_named(n_antennas_5, n_antennas_5_param, int, S_IRUSR);
2034MODULE_PARM_DESC(n_antennas_5,
2035 "Number of installed 5GHz antennas: 1 (default) or 2");
2036
2037module_param_named(low_band_component, low_band_component_param, int,
2038 S_IRUSR);
Luciano Coelho858403a2012-05-10 12:14:17 +03002039MODULE_PARM_DESC(low_band_component, "Low band component: u8 "
2040 "(default is 0x01)");
2041
Arik Nemtsov17d97712012-05-29 12:44:12 +03002042module_param_named(low_band_component_type, low_band_component_type_param,
2043 int, S_IRUSR);
Luciano Coelho858403a2012-05-10 12:14:17 +03002044MODULE_PARM_DESC(low_band_component_type, "Low band component type: u8 "
2045 "(default is 0x05 or 0x06 depending on the board_type)");
2046
Arik Nemtsov17d97712012-05-29 12:44:12 +03002047module_param_named(high_band_component, high_band_component_param, int,
2048 S_IRUSR);
Luciano Coelho858403a2012-05-10 12:14:17 +03002049MODULE_PARM_DESC(high_band_component, "High band component: u8, "
2050 "(default is 0x01)");
2051
Arik Nemtsov17d97712012-05-29 12:44:12 +03002052module_param_named(high_band_component_type, high_band_component_type_param,
2053 int, S_IRUSR);
Luciano Coelho858403a2012-05-10 12:14:17 +03002054MODULE_PARM_DESC(high_band_component_type, "High band component type: u8 "
2055 "(default is 0x09)");
2056
Arik Nemtsov17d97712012-05-29 12:44:12 +03002057module_param_named(pwr_limit_reference_11_abg,
2058 pwr_limit_reference_11_abg_param, int, S_IRUSR);
Luciano Coelho7b03c302012-05-10 12:14:18 +03002059MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
2060 "(default is 0xc8)");
2061
Arik Nemtsov09aad142012-06-10 22:57:30 +03002062module_param_named(num_rx_desc,
2063 num_rx_desc_param, int, S_IRUSR);
2064MODULE_PARM_DESC(num_rx_desc_param,
2065 "Number of Rx descriptors: u8 (default is 32)");
2066
Luciano Coelho9a1a6992012-05-10 12:13:06 +03002067MODULE_LICENSE("GPL v2");
2068MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Luciano Coelho0cd65432012-05-10 12:13:11 +03002069MODULE_FIRMWARE(WL18XX_FW_NAME);