blob: 6c1000d1735beb625fe315a4b463118a3e640c5b [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>
Luciano Coelho9a1a6992012-05-10 12:13:06 +030027
28#include "../wlcore/wlcore.h"
29#include "../wlcore/debug.h"
Luciano Coelho46a1d512012-05-10 12:13:12 +030030#include "../wlcore/io.h"
31#include "../wlcore/acx.h"
Arik Nemtsovfb0f2e42012-05-10 12:13:18 +030032#include "../wlcore/tx.h"
Arik Nemtsov9c809f82012-05-10 12:13:23 +030033#include "../wlcore/rx.h"
Luciano Coelho46a1d512012-05-10 12:13:12 +030034#include "../wlcore/boot.h"
Luciano Coelho9a1a6992012-05-10 12:13:06 +030035
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +030036#include "reg.h"
Luciano Coelho46a1d512012-05-10 12:13:12 +030037#include "conf.h"
Eliad Pellerfcab1892012-11-22 18:06:18 +020038#include "cmd.h"
Luciano Coelhob8422dc2012-05-10 12:13:26 +030039#include "acx.h"
Arik Nemtsov872b3452012-05-10 12:13:25 +030040#include "tx.h"
Luciano Coelho274c66c2012-05-10 12:13:13 +030041#include "wl18xx.h"
Luciano Coelhobe652022012-05-10 12:13:41 +030042#include "io.h"
Eliad Peller78e28062012-11-22 18:06:15 +020043#include "scan.h"
Eliad Pellerc50a2822012-11-22 18:06:19 +020044#include "event.h"
Luciano Coelho8c0ea102012-05-10 12:14:09 +030045#include "debugfs.h"
Arik Nemtsov1349c422012-05-10 12:13:16 +030046
Arik Nemtsov169da042012-05-10 12:13:28 +030047#define WL18XX_RX_CHECKSUM_MASK 0x40
48
Yair Shapirac68cc0f2012-07-05 15:11:30 +000049static char *ht_mode_param = NULL;
50static char *board_type_param = NULL;
Assaf Azulay3d62eb52012-05-10 12:14:23 +030051static bool checksum_param = false;
Arik Nemtsov09aad142012-06-10 22:57:30 +030052static int num_rx_desc_param = -1;
Arik Nemtsov17d97712012-05-29 12:44:12 +030053
54/* phy paramters */
55static int dc2dc_param = -1;
56static int n_antennas_2_param = -1;
57static int n_antennas_5_param = -1;
58static int low_band_component_param = -1;
59static int low_band_component_type_param = -1;
60static int high_band_component_param = -1;
61static int high_band_component_type_param = -1;
62static int pwr_limit_reference_11_abg_param = -1;
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +030063
Arik Nemtsovf648eab2012-05-10 12:13:20 +030064static const u8 wl18xx_rate_to_idx_2ghz[] = {
65 /* MCS rates are used only with 11n */
66 15, /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
67 14, /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
68 13, /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
69 12, /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
70 11, /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
71 10, /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
72 9, /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
73 8, /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
74 7, /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
75 6, /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
76 5, /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
77 4, /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
78 3, /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
79 2, /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
80 1, /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
81 0, /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
82
83 11, /* WL18XX_CONF_HW_RXTX_RATE_54 */
84 10, /* WL18XX_CONF_HW_RXTX_RATE_48 */
85 9, /* WL18XX_CONF_HW_RXTX_RATE_36 */
86 8, /* WL18XX_CONF_HW_RXTX_RATE_24 */
87
88 /* TI-specific rate */
89 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22 */
90
91 7, /* WL18XX_CONF_HW_RXTX_RATE_18 */
92 6, /* WL18XX_CONF_HW_RXTX_RATE_12 */
93 3, /* WL18XX_CONF_HW_RXTX_RATE_11 */
94 5, /* WL18XX_CONF_HW_RXTX_RATE_9 */
95 4, /* WL18XX_CONF_HW_RXTX_RATE_6 */
96 2, /* WL18XX_CONF_HW_RXTX_RATE_5_5 */
97 1, /* WL18XX_CONF_HW_RXTX_RATE_2 */
98 0 /* WL18XX_CONF_HW_RXTX_RATE_1 */
99};
100
101static const u8 wl18xx_rate_to_idx_5ghz[] = {
102 /* MCS rates are used only with 11n */
103 15, /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
104 14, /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
105 13, /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
106 12, /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
107 11, /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
108 10, /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
109 9, /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
110 8, /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
111 7, /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
112 6, /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
113 5, /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
114 4, /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
115 3, /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
116 2, /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
117 1, /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
118 0, /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
119
120 7, /* WL18XX_CONF_HW_RXTX_RATE_54 */
121 6, /* WL18XX_CONF_HW_RXTX_RATE_48 */
122 5, /* WL18XX_CONF_HW_RXTX_RATE_36 */
123 4, /* WL18XX_CONF_HW_RXTX_RATE_24 */
124
125 /* TI-specific rate */
126 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22 */
127
128 3, /* WL18XX_CONF_HW_RXTX_RATE_18 */
129 2, /* WL18XX_CONF_HW_RXTX_RATE_12 */
130 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_11 */
131 1, /* WL18XX_CONF_HW_RXTX_RATE_9 */
132 0, /* WL18XX_CONF_HW_RXTX_RATE_6 */
133 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_5_5 */
134 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_2 */
135 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_1 */
136};
137
138static const u8 *wl18xx_band_rate_to_idx[] = {
139 [IEEE80211_BAND_2GHZ] = wl18xx_rate_to_idx_2ghz,
140 [IEEE80211_BAND_5GHZ] = wl18xx_rate_to_idx_5ghz
141};
142
143enum wl18xx_hw_rates {
144 WL18XX_CONF_HW_RXTX_RATE_MCS15 = 0,
145 WL18XX_CONF_HW_RXTX_RATE_MCS14,
146 WL18XX_CONF_HW_RXTX_RATE_MCS13,
147 WL18XX_CONF_HW_RXTX_RATE_MCS12,
148 WL18XX_CONF_HW_RXTX_RATE_MCS11,
149 WL18XX_CONF_HW_RXTX_RATE_MCS10,
150 WL18XX_CONF_HW_RXTX_RATE_MCS9,
151 WL18XX_CONF_HW_RXTX_RATE_MCS8,
152 WL18XX_CONF_HW_RXTX_RATE_MCS7,
153 WL18XX_CONF_HW_RXTX_RATE_MCS6,
154 WL18XX_CONF_HW_RXTX_RATE_MCS5,
155 WL18XX_CONF_HW_RXTX_RATE_MCS4,
156 WL18XX_CONF_HW_RXTX_RATE_MCS3,
157 WL18XX_CONF_HW_RXTX_RATE_MCS2,
158 WL18XX_CONF_HW_RXTX_RATE_MCS1,
159 WL18XX_CONF_HW_RXTX_RATE_MCS0,
160 WL18XX_CONF_HW_RXTX_RATE_54,
161 WL18XX_CONF_HW_RXTX_RATE_48,
162 WL18XX_CONF_HW_RXTX_RATE_36,
163 WL18XX_CONF_HW_RXTX_RATE_24,
164 WL18XX_CONF_HW_RXTX_RATE_22,
165 WL18XX_CONF_HW_RXTX_RATE_18,
166 WL18XX_CONF_HW_RXTX_RATE_12,
167 WL18XX_CONF_HW_RXTX_RATE_11,
168 WL18XX_CONF_HW_RXTX_RATE_9,
169 WL18XX_CONF_HW_RXTX_RATE_6,
170 WL18XX_CONF_HW_RXTX_RATE_5_5,
171 WL18XX_CONF_HW_RXTX_RATE_2,
172 WL18XX_CONF_HW_RXTX_RATE_1,
173 WL18XX_CONF_HW_RXTX_RATE_MAX,
174};
175
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300176static struct wlcore_conf wl18xx_conf = {
177 .sg = {
178 .params = {
179 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
180 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
181 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
182 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
183 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
184 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
185 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
186 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
187 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
188 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
189 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
190 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
191 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
192 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
193 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
194 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
195 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
196 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
197 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
198 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
199 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
200 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
201 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
202 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
203 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
204 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
205 /* active scan params */
206 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
207 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
208 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
209 /* passive scan params */
210 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
211 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
212 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
213 /* passive scan in dual antenna params */
214 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
215 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
216 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
217 /* general params */
218 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
219 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
220 [CONF_SG_BEACON_MISS_PERCENT] = 60,
221 [CONF_SG_DHCP_TIME] = 5000,
222 [CONF_SG_RXT] = 1200,
223 [CONF_SG_TXT] = 1000,
224 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
225 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
226 [CONF_SG_HV3_MAX_SERVED] = 6,
227 [CONF_SG_PS_POLL_TIMEOUT] = 10,
228 [CONF_SG_UPSD_TIMEOUT] = 10,
229 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
230 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
231 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
232 /* AP params */
233 [CONF_AP_BEACON_MISS_TX] = 3,
234 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
235 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
236 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
237 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
238 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
239 /* CTS Diluting params */
240 [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
241 [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
242 },
243 .state = CONF_SG_PROTECTIVE,
244 },
245 .rx = {
246 .rx_msdu_life_time = 512000,
247 .packet_detection_threshold = 0,
248 .ps_poll_timeout = 15,
249 .upsd_timeout = 15,
250 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
251 .rx_cca_threshold = 0,
252 .irq_blk_threshold = 0xFFFF,
253 .irq_pkt_threshold = 0,
254 .irq_timeout = 600,
255 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
256 },
257 .tx = {
258 .tx_energy_detection = 0,
259 .sta_rc_conf = {
260 .enabled_rates = 0,
261 .short_retry_limit = 10,
262 .long_retry_limit = 10,
263 .aflags = 0,
264 },
265 .ac_conf_count = 4,
266 .ac_conf = {
267 [CONF_TX_AC_BE] = {
268 .ac = CONF_TX_AC_BE,
269 .cw_min = 15,
270 .cw_max = 63,
271 .aifsn = 3,
272 .tx_op_limit = 0,
273 },
274 [CONF_TX_AC_BK] = {
275 .ac = CONF_TX_AC_BK,
276 .cw_min = 15,
277 .cw_max = 63,
278 .aifsn = 7,
279 .tx_op_limit = 0,
280 },
281 [CONF_TX_AC_VI] = {
282 .ac = CONF_TX_AC_VI,
283 .cw_min = 15,
284 .cw_max = 63,
285 .aifsn = CONF_TX_AIFS_PIFS,
286 .tx_op_limit = 3008,
287 },
288 [CONF_TX_AC_VO] = {
289 .ac = CONF_TX_AC_VO,
290 .cw_min = 15,
291 .cw_max = 63,
292 .aifsn = CONF_TX_AIFS_PIFS,
293 .tx_op_limit = 1504,
294 },
295 },
296 .max_tx_retries = 100,
297 .ap_aging_period = 300,
298 .tid_conf_count = 4,
299 .tid_conf = {
300 [CONF_TX_AC_BE] = {
301 .queue_id = CONF_TX_AC_BE,
302 .channel_type = CONF_CHANNEL_TYPE_EDCF,
303 .tsid = CONF_TX_AC_BE,
304 .ps_scheme = CONF_PS_SCHEME_LEGACY,
305 .ack_policy = CONF_ACK_POLICY_LEGACY,
306 .apsd_conf = {0, 0},
307 },
308 [CONF_TX_AC_BK] = {
309 .queue_id = CONF_TX_AC_BK,
310 .channel_type = CONF_CHANNEL_TYPE_EDCF,
311 .tsid = CONF_TX_AC_BK,
312 .ps_scheme = CONF_PS_SCHEME_LEGACY,
313 .ack_policy = CONF_ACK_POLICY_LEGACY,
314 .apsd_conf = {0, 0},
315 },
316 [CONF_TX_AC_VI] = {
317 .queue_id = CONF_TX_AC_VI,
318 .channel_type = CONF_CHANNEL_TYPE_EDCF,
319 .tsid = CONF_TX_AC_VI,
320 .ps_scheme = CONF_PS_SCHEME_LEGACY,
321 .ack_policy = CONF_ACK_POLICY_LEGACY,
322 .apsd_conf = {0, 0},
323 },
324 [CONF_TX_AC_VO] = {
325 .queue_id = CONF_TX_AC_VO,
326 .channel_type = CONF_CHANNEL_TYPE_EDCF,
327 .tsid = CONF_TX_AC_VO,
328 .ps_scheme = CONF_PS_SCHEME_LEGACY,
329 .ack_policy = CONF_ACK_POLICY_LEGACY,
330 .apsd_conf = {0, 0},
331 },
332 },
333 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
334 .tx_compl_timeout = 350,
335 .tx_compl_threshold = 10,
336 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
337 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
338 .tmpl_short_retry_limit = 10,
339 .tmpl_long_retry_limit = 10,
340 .tx_watchdog_timeout = 5000,
Arik Nemtsov0e810472012-11-27 08:45:00 +0200341 .slow_link_thold = 3,
342 .fast_link_thold = 30,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300343 },
344 .conn = {
345 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
346 .listen_interval = 1,
347 .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
348 .suspend_listen_interval = 3,
349 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Eliad Peller186b5a72012-05-15 16:35:20 +0300350 .bcn_filt_ie_count = 3,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300351 .bcn_filt_ie = {
352 [0] = {
353 .ie = WLAN_EID_CHANNEL_SWITCH,
354 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
355 },
356 [1] = {
357 .ie = WLAN_EID_HT_OPERATION,
358 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
359 },
Eliad Peller186b5a72012-05-15 16:35:20 +0300360 [2] = {
361 .ie = WLAN_EID_ERP_INFO,
362 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
363 },
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300364 },
Igal Chernobelsky7b052212012-05-15 17:08:57 +0300365 .synch_fail_thold = 12,
366 .bss_lose_timeout = 400,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300367 .beacon_rx_timeout = 10000,
368 .broadcast_timeout = 20000,
369 .rx_broadcast_in_ps = 1,
370 .ps_poll_threshold = 10,
371 .bet_enable = CONF_BET_MODE_ENABLE,
372 .bet_max_consecutive = 50,
373 .psm_entry_retries = 8,
374 .psm_exit_retries = 16,
375 .psm_entry_nullfunc_retries = 3,
Arik Nemtsov0fc1d2e2012-07-03 11:34:43 +0300376 .dynamic_ps_timeout = 1500,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300377 .forced_ps = false,
378 .keep_alive_interval = 55000,
379 .max_listen_interval = 20,
Arik Nemtsov66340e52012-06-10 17:09:22 +0300380 .sta_sleep_auth = WL1271_PSM_ILLEGAL,
Ram Amrani6d5a7482014-12-29 08:24:04 +0200381 .suspend_rx_ba_activity = 0,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300382 },
383 .itrim = {
384 .enable = false,
385 .timeout = 50000,
386 },
387 .pm_config = {
388 .host_clk_settling_time = 5000,
Luciano Coelho648f6ed2012-06-07 23:39:24 +0300389 .host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300390 },
391 .roam_trigger = {
392 .trigger_pacing = 1,
393 .avg_weight_rssi_beacon = 20,
394 .avg_weight_rssi_data = 10,
395 .avg_weight_snr_beacon = 20,
396 .avg_weight_snr_data = 10,
397 },
398 .scan = {
399 .min_dwell_time_active = 7500,
400 .max_dwell_time_active = 30000,
Eyal Shapira5d3a1602012-12-08 02:58:23 +0200401 .min_dwell_time_active_long = 25000,
402 .max_dwell_time_active_long = 50000,
Eliad Peller7c482c12012-11-26 18:05:40 +0200403 .dwell_time_passive = 100000,
404 .dwell_time_dfs = 150000,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300405 .num_probe_reqs = 2,
406 .split_scan_timeout = 50000,
407 },
408 .sched_scan = {
409 /*
410 * Values are in TU/1000 but since sched scan FW command
411 * params are in TUs rounding up may occur.
412 */
413 .base_dwell_time = 7500,
414 .max_dwell_time_delta = 22500,
415 /* based on 250bits per probe @1Mbps */
416 .dwell_time_delta_per_probe = 2000,
417 /* based on 250bits per probe @6Mbps (plus a bit more) */
418 .dwell_time_delta_per_probe_5 = 350,
419 .dwell_time_passive = 100000,
420 .dwell_time_dfs = 150000,
421 .num_probe_reqs = 2,
422 .rssi_threshold = -90,
423 .snr_threshold = 0,
424 },
425 .ht = {
Ido Reis9ae48ae2012-06-25 18:51:54 +0300426 .rx_ba_win_size = 32,
Luciano Coelho3507efa2012-05-10 12:14:21 +0300427 .tx_ba_win_size = 64,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300428 .inactivity_timeout = 10000,
429 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
430 },
431 .mem = {
432 .num_stations = 1,
433 .ssid_profiles = 1,
434 .rx_block_num = 40,
435 .tx_min_block_num = 40,
436 .dynamic_memory = 1,
437 .min_req_tx_blocks = 45,
438 .min_req_rx_blocks = 22,
439 .tx_min = 27,
440 },
441 .fm_coex = {
442 .enable = true,
443 .swallow_period = 5,
444 .n_divider_fref_set_1 = 0xff, /* default */
445 .n_divider_fref_set_2 = 12,
Victor Goldenshtein461b9582012-05-15 17:15:40 +0300446 .m_divider_fref_set_1 = 0xffff,
447 .m_divider_fref_set_2 = 148, /* default */
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300448 .coex_pll_stabilization_time = 0xffffffff, /* default */
449 .ldo_stabilization_time = 0xffff, /* default */
450 .fm_disturbed_band_margin = 0xff, /* default */
451 .swallow_clk_diff = 0xff, /* default */
452 },
453 .rx_streaming = {
454 .duration = 150,
455 .queues = 0x1,
456 .interval = 20,
457 .always = 0,
458 },
459 .fwlog = {
Ido Reis9d8146d2013-09-09 12:24:37 +0300460 .mode = WL12XX_FWLOG_CONTINUOUS,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300461 .mem_blocks = 2,
462 .severity = 0,
463 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
Ido Reis9d8146d2013-09-09 12:24:37 +0300464 .output = WL12XX_FWLOG_OUTPUT_DBG_PINS,
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300465 .threshold = 0,
466 },
467 .rate = {
468 .rate_retry_score = 32000,
469 .per_add = 8192,
470 .per_th1 = 2048,
471 .per_th2 = 4096,
472 .max_per = 8100,
473 .inverse_curiosity_factor = 5,
474 .tx_fail_low_th = 4,
475 .tx_fail_high_th = 10,
476 .per_alpha_shift = 4,
477 .per_add_shift = 13,
478 .per_beta1_shift = 10,
479 .per_beta2_shift = 8,
480 .rate_check_up = 2,
481 .rate_check_down = 12,
482 .rate_retry_policy = {
483 0x00, 0x00, 0x00, 0x00, 0x00,
484 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x00, 0x00, 0x00,
486 },
487 },
488 .hangover = {
489 .recover_time = 0,
490 .hangover_period = 20,
491 .dynamic_mode = 1,
492 .early_termination_mode = 1,
493 .max_period = 20,
494 .min_period = 1,
495 .increase_delta = 1,
496 .decrease_delta = 2,
497 .quiet_time = 4,
498 .increase_time = 1,
499 .window_size = 16,
500 },
Yair Shapira72303412012-11-26 18:05:50 +0200501 .recovery = {
502 .bug_on_recovery = 0,
503 .no_recovery = 0,
504 },
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300505};
506
507static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
Yair Shapirac68cc0f2012-07-05 15:11:30 +0000508 .ht = {
Igal Chernobelsky50e4c902013-09-09 12:24:32 +0300509 .mode = HT_MODE_WIDE,
Yair Shapirac68cc0f2012-07-05 15:11:30 +0000510 },
Luciano Coelho46a1d512012-05-10 12:13:12 +0300511 .phy = {
512 .phy_standalone = 0x00,
513 .primary_clock_setting_time = 0x05,
514 .clock_valid_on_wake_up = 0x00,
515 .secondary_clock_setting_time = 0x05,
Yair Shapirac68cc0f2012-07-05 15:11:30 +0000516 .board_type = BOARD_TYPE_HDK_18XX,
Luciano Coelho46a1d512012-05-10 12:13:12 +0300517 .auto_detect = 0x00,
518 .dedicated_fem = FEM_NONE,
Ido Reise1c497c2012-07-13 00:12:08 +0300519 .low_band_component = COMPONENT_3_WAY_SWITCH,
Igal Chernobelsky50e4c902013-09-09 12:24:32 +0300520 .low_band_component_type = 0x05,
Luciano Coelho46a1d512012-05-10 12:13:12 +0300521 .high_band_component = COMPONENT_2_WAY_SWITCH,
522 .high_band_component_type = 0x09,
Luciano Coelho46a1d512012-05-10 12:13:12 +0300523 .tcxo_ldo_voltage = 0x00,
524 .xtal_itrim_val = 0x04,
525 .srf_state = 0x00,
526 .io_configuration = 0x01,
527 .sdio_configuration = 0x00,
528 .settings = 0x00,
529 .enable_clpc = 0x00,
530 .enable_tx_low_pwr_on_siso_rdl = 0x00,
531 .rx_profile = 0x00,
Yair Shapirad88949b2012-11-27 08:44:43 +0200532 .pwr_limit_reference_11_abg = 0x64,
533 .per_chan_pwr_limit_arr_11abg = {
534 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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 },
551 .pwr_limit_reference_11p = 0x64,
Victor Goldenshtein1d614662012-12-27 15:49:47 +0200552 .per_chan_bo_mode_11_abg = { 0x00, 0x00, 0x00, 0x00,
553 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00,
555 0x00 },
556 .per_chan_bo_mode_11_p = { 0x00, 0x00, 0x00, 0x00 },
Yair Shapirad88949b2012-11-27 08:44:43 +0200557 .per_chan_pwr_limit_arr_11p = { 0xff, 0xff, 0xff, 0xff,
558 0xff, 0xff, 0xff },
Ido Reis16ea4732012-04-23 16:49:19 +0300559 .psat = 0,
Arik Nemtsov17d97712012-05-29 12:44:12 +0300560 .external_pa_dc2dc = 0,
Yair Shapirad88949b2012-11-27 08:44:43 +0200561 .number_of_assembled_ant2_4 = 2,
Arik Nemtsov17d97712012-05-29 12:44:12 +0300562 .number_of_assembled_ant5 = 1,
Igal Chernobelsky50e4c902013-09-09 12:24:32 +0300563 .low_power_val = 0xff,
564 .med_power_val = 0xff,
565 .high_power_val = 0xff,
566 .low_power_val_2nd = 0xff,
567 .med_power_val_2nd = 0xff,
568 .high_power_val_2nd = 0xff,
Ido Reisec4f4b72012-11-27 08:44:42 +0200569 .tx_rf_margin = 1,
Luciano Coelho46a1d512012-05-10 12:13:12 +0300570 },
571};
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +0300572
Luciano Coelho82b890c2012-05-10 12:13:09 +0300573static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
574 [PART_TOP_PRCM_ELP_SOC] = {
575 .mem = { .start = 0x00A02000, .size = 0x00010000 },
576 .reg = { .start = 0x00807000, .size = 0x00005000 },
577 .mem2 = { .start = 0x00800000, .size = 0x0000B000 },
578 .mem3 = { .start = 0x00000000, .size = 0x00000000 },
579 },
580 [PART_DOWN] = {
581 .mem = { .start = 0x00000000, .size = 0x00014000 },
582 .reg = { .start = 0x00810000, .size = 0x0000BFFF },
583 .mem2 = { .start = 0x00000000, .size = 0x00000000 },
584 .mem3 = { .start = 0x00000000, .size = 0x00000000 },
585 },
586 [PART_BOOT] = {
587 .mem = { .start = 0x00700000, .size = 0x0000030c },
588 .reg = { .start = 0x00802000, .size = 0x00014578 },
589 .mem2 = { .start = 0x00B00404, .size = 0x00001000 },
590 .mem3 = { .start = 0x00C00000, .size = 0x00000400 },
591 },
592 [PART_WORK] = {
593 .mem = { .start = 0x00800000, .size = 0x000050FC },
594 .reg = { .start = 0x00B00404, .size = 0x00001000 },
595 .mem2 = { .start = 0x00C00000, .size = 0x00000400 },
596 .mem3 = { .start = 0x00000000, .size = 0x00000000 },
597 },
598 [PART_PHY_INIT] = {
Ido Reise3b8bbb2012-11-27 08:44:51 +0200599 .mem = { .start = WL18XX_PHY_INIT_MEM_ADDR,
600 .size = WL18XX_PHY_INIT_MEM_SIZE },
Luciano Coelho82b890c2012-05-10 12:13:09 +0300601 .reg = { .start = 0x00000000, .size = 0x00000000 },
602 .mem2 = { .start = 0x00000000, .size = 0x00000000 },
603 .mem3 = { .start = 0x00000000, .size = 0x00000000 },
604 },
605};
606
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +0300607static const int wl18xx_rtable[REG_TABLE_LEN] = {
608 [REG_ECPU_CONTROL] = WL18XX_REG_ECPU_CONTROL,
609 [REG_INTERRUPT_NO_CLEAR] = WL18XX_REG_INTERRUPT_NO_CLEAR,
610 [REG_INTERRUPT_ACK] = WL18XX_REG_INTERRUPT_ACK,
611 [REG_COMMAND_MAILBOX_PTR] = WL18XX_REG_COMMAND_MAILBOX_PTR,
612 [REG_EVENT_MAILBOX_PTR] = WL18XX_REG_EVENT_MAILBOX_PTR,
613 [REG_INTERRUPT_TRIG] = WL18XX_REG_INTERRUPT_TRIG_H,
614 [REG_INTERRUPT_MASK] = WL18XX_REG_INTERRUPT_MASK,
Arik Nemtsov1c351da2012-05-10 12:13:39 +0300615 [REG_PC_ON_RECOVERY] = WL18XX_SCR_PAD4,
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +0300616 [REG_CHIP_ID_B] = WL18XX_REG_CHIP_ID_B,
617 [REG_CMD_MBOX_ADDRESS] = WL18XX_CMD_MBOX_ADDRESS,
618
619 /* data access memory addresses, used with partition translation */
620 [REG_SLV_MEM_DATA] = WL18XX_SLV_MEM_DATA,
621 [REG_SLV_REG_DATA] = WL18XX_SLV_REG_DATA,
622
623 /* raw data access memory addresses */
624 [REG_RAW_FW_STATUS_ADDR] = WL18XX_FW_STATUS_ADDR,
625};
626
Victor Goldenshteinef47d322013-09-17 18:41:28 +0300627static const struct wl18xx_clk_cfg wl18xx_clk_table_coex[NUM_CLOCK_CONFIGS] = {
628 [CLOCK_CONFIG_16_2_M] = { 8, 121, 0, 0, false },
629 [CLOCK_CONFIG_16_368_M] = { 8, 120, 0, 0, false },
630 [CLOCK_CONFIG_16_8_M] = { 8, 117, 0, 0, false },
631 [CLOCK_CONFIG_19_2_M] = { 10, 128, 0, 0, false },
632 [CLOCK_CONFIG_26_M] = { 11, 104, 0, 0, false },
633 [CLOCK_CONFIG_32_736_M] = { 8, 120, 0, 0, false },
634 [CLOCK_CONFIG_33_6_M] = { 8, 117, 0, 0, false },
635 [CLOCK_CONFIG_38_468_M] = { 10, 128, 0, 0, false },
636 [CLOCK_CONFIG_52_M] = { 11, 104, 0, 0, false },
637};
638
Luciano Coelhobe652022012-05-10 12:13:41 +0300639static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
640 [CLOCK_CONFIG_16_2_M] = { 7, 104, 801, 4, true },
641 [CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true },
642 [CLOCK_CONFIG_16_8_M] = { 7, 100, 0, 0, false },
643 [CLOCK_CONFIG_19_2_M] = { 8, 100, 0, 0, false },
644 [CLOCK_CONFIG_26_M] = { 13, 120, 0, 0, false },
645 [CLOCK_CONFIG_32_736_M] = { 9, 132, 3751, 4, true },
646 [CLOCK_CONFIG_33_6_M] = { 7, 100, 0, 0, false },
647 [CLOCK_CONFIG_38_468_M] = { 8, 100, 0, 0, false },
648 [CLOCK_CONFIG_52_M] = { 13, 120, 0, 0, false },
649};
650
Luciano Coelho0cd65432012-05-10 12:13:11 +0300651/* TODO: maybe move to a new header file? */
Eliad Peller028e7242014-02-10 13:47:25 +0200652#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-3.bin"
Luciano Coelho0cd65432012-05-10 12:13:11 +0300653
654static int wl18xx_identify_chip(struct wl1271 *wl)
655{
656 int ret = 0;
657
658 switch (wl->chip.id) {
Ido Reis73395a792012-04-22 20:45:52 +0300659 case CHIP_ID_185x_PG20:
660 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG20)",
661 wl->chip.id);
662 wl->sr_fw_name = WL18XX_FW_NAME;
663 /* wl18xx uses the same firmware for PLT */
664 wl->plt_fw_name = WL18XX_FW_NAME;
Eliad Peller2718bf42012-11-27 08:44:47 +0200665 wl->quirks |= WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
Arik Nemtsovbf7c46a2012-06-11 10:41:08 +0300666 WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
Victor Goldenshtein01b3c0e2012-06-14 09:47:40 +0300667 WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
Eliad Peller78e28062012-11-22 18:06:15 +0200668 WLCORE_QUIRK_TX_PAD_LAST_FRAME |
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +0200669 WLCORE_QUIRK_REGDOMAIN_CONF |
Eliad Peller78e28062012-11-22 18:06:15 +0200670 WLCORE_QUIRK_DUAL_PROBE_TMPL;
Arik Nemtsov4a1ccce2012-06-25 17:46:40 +0300671
Luciano Coelho8675f9a2012-11-27 15:52:00 +0200672 wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER,
673 WL18XX_IFTYPE_VER, WL18XX_MAJOR_VER,
674 WL18XX_SUBTYPE_VER, WL18XX_MINOR_VER,
675 /* there's no separate multi-role FW */
676 0, 0, 0, 0);
Ido Reis73395a792012-04-22 20:45:52 +0300677 break;
Luciano Coelho0cd65432012-05-10 12:13:11 +0300678 case CHIP_ID_185x_PG10:
Luciano Coelhoe59bec12012-06-25 14:15:55 +0300679 wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
680 wl->chip.id);
681 ret = -ENODEV;
682 goto out;
Luciano Coelho0cd65432012-05-10 12:13:11 +0300683
Luciano Coelho0cd65432012-05-10 12:13:11 +0300684 default:
685 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
686 ret = -ENODEV;
687 goto out;
688 }
689
Igal Chernobelskyc83cb802013-09-09 12:24:38 +0300690 wl->fw_mem_block_size = 272;
691 wl->fwlog_end = 0x40000000;
692
Eliad Peller78e28062012-11-22 18:06:15 +0200693 wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
694 wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
695 wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
696 wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
Eliad Peller0a1c7202012-11-22 18:06:16 +0200697 wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
Igal Chernobelskyd21553f2013-03-12 17:19:35 +0200698 wl->ba_rx_session_count_max = WL18XX_RX_BA_MAX_SESSIONS;
Luciano Coelho0cd65432012-05-10 12:13:11 +0300699out:
700 return ret;
701}
702
Ido Yariv61343232012-06-18 15:50:21 +0300703static int wl18xx_set_clk(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300704{
Ido Yariv61343232012-06-18 15:50:21 +0300705 u16 clk_freq;
706 int ret;
Luciano Coelhod5b59272012-05-10 12:13:38 +0300707
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300708 ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
709 if (ret < 0)
710 goto out;
Luciano Coelhobe652022012-05-10 12:13:41 +0300711
712 /* TODO: PG2: apparently we need to read the clk type */
713
Ido Yariv61343232012-06-18 15:50:21 +0300714 ret = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT, &clk_freq);
715 if (ret < 0)
716 goto out;
717
Luciano Coelhobe652022012-05-10 12:13:41 +0300718 wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq,
719 wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m,
720 wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q,
721 wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit");
722
Victor Goldenshteinef47d322013-09-17 18:41:28 +0300723 /* coex PLL configuration */
724 ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_N,
725 wl18xx_clk_table_coex[clk_freq].n);
726 if (ret < 0)
727 goto out;
728
729 ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_M,
730 wl18xx_clk_table_coex[clk_freq].m);
731 if (ret < 0)
732 goto out;
733
734 /* bypass the swallowing logic */
735 ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
736 PLLSH_COEX_PLL_SWALLOW_EN_VAL1);
737 if (ret < 0)
738 goto out;
739
Ido Yariv61343232012-06-18 15:50:21 +0300740 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
741 wl18xx_clk_table[clk_freq].n);
742 if (ret < 0)
743 goto out;
744
745 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M,
746 wl18xx_clk_table[clk_freq].m);
747 if (ret < 0)
748 goto out;
Luciano Coelhobe652022012-05-10 12:13:41 +0300749
750 if (wl18xx_clk_table[clk_freq].swallow) {
751 /* first the 16 lower bits */
Ido Yariv61343232012-06-18 15:50:21 +0300752 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1,
753 wl18xx_clk_table[clk_freq].q &
754 PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK);
755 if (ret < 0)
756 goto out;
757
Luciano Coelhobe652022012-05-10 12:13:41 +0300758 /* then the 16 higher bits, masked out */
Ido Yariv61343232012-06-18 15:50:21 +0300759 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2,
760 (wl18xx_clk_table[clk_freq].q >> 16) &
761 PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK);
762 if (ret < 0)
763 goto out;
Luciano Coelhobe652022012-05-10 12:13:41 +0300764
765 /* first the 16 lower bits */
Ido Yariv61343232012-06-18 15:50:21 +0300766 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1,
767 wl18xx_clk_table[clk_freq].p &
768 PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK);
769 if (ret < 0)
770 goto out;
771
Luciano Coelhobe652022012-05-10 12:13:41 +0300772 /* then the 16 higher bits, masked out */
Ido Yariv61343232012-06-18 15:50:21 +0300773 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2,
774 (wl18xx_clk_table[clk_freq].p >> 16) &
775 PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK);
Luciano Coelhobe652022012-05-10 12:13:41 +0300776 } else {
Ido Yariv61343232012-06-18 15:50:21 +0300777 ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN,
778 PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
Luciano Coelhobe652022012-05-10 12:13:41 +0300779 }
Ido Yariv61343232012-06-18 15:50:21 +0300780
Victor Goldenshteinef47d322013-09-17 18:41:28 +0300781 /* choose WCS PLL */
782 ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_SEL,
783 PLLSH_WL_PLL_SEL_WCS_PLL);
784 if (ret < 0)
785 goto out;
786
787 /* enable both PLLs */
788 ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL1);
789 if (ret < 0)
790 goto out;
791
792 udelay(1000);
793
794 /* disable coex PLL */
795 ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL2);
796 if (ret < 0)
797 goto out;
798
799 /* reset the swallowing logic */
800 ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
801 PLLSH_COEX_PLL_SWALLOW_EN_VAL2);
802 if (ret < 0)
803 goto out;
804
Ido Yariv61343232012-06-18 15:50:21 +0300805out:
806 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300807}
808
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300809static int wl18xx_boot_soft_reset(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300810{
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300811 int ret;
812
Luciano Coelho46a1d512012-05-10 12:13:12 +0300813 /* disable Rx/Tx */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300814 ret = wlcore_write32(wl, WL18XX_ENABLE, 0x0);
815 if (ret < 0)
816 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300817
818 /* disable auto calibration on start*/
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300819 ret = wlcore_write32(wl, WL18XX_SPARE_A2, 0xffff);
820
821out:
822 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300823}
824
825static int wl18xx_pre_boot(struct wl1271 *wl)
826{
Ido Yariv61343232012-06-18 15:50:21 +0300827 int ret;
828
829 ret = wl18xx_set_clk(wl);
830 if (ret < 0)
831 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300832
833 /* Continue the ELP wake up sequence */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300834 ret = wlcore_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
835 if (ret < 0)
836 goto out;
837
Luciano Coelho46a1d512012-05-10 12:13:12 +0300838 udelay(500);
839
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300840 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
841 if (ret < 0)
842 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300843
844 /* Disable interrupts */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300845 ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
846 if (ret < 0)
847 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300848
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300849 ret = wl18xx_boot_soft_reset(wl);
Luciano Coelho46a1d512012-05-10 12:13:12 +0300850
Ido Yariv61343232012-06-18 15:50:21 +0300851out:
852 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300853}
854
Ido Yariv61343232012-06-18 15:50:21 +0300855static int wl18xx_pre_upload(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300856{
857 u32 tmp;
Ido Yariv61343232012-06-18 15:50:21 +0300858 int ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300859
Ido Reise3b8bbb2012-11-27 08:44:51 +0200860 BUILD_BUG_ON(sizeof(struct wl18xx_mac_and_phy_params) >
861 WL18XX_PHY_INIT_MEM_SIZE);
862
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300863 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
864 if (ret < 0)
865 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300866
867 /* TODO: check if this is all needed */
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300868 ret = wlcore_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND);
869 if (ret < 0)
870 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300871
Ido Yariv61343232012-06-18 15:50:21 +0300872 ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp);
873 if (ret < 0)
874 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300875
876 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
877
Ido Yariv61343232012-06-18 15:50:21 +0300878 ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp);
Ido Reise3b8bbb2012-11-27 08:44:51 +0200879 if (ret < 0)
880 goto out;
881
882 /*
883 * Workaround for FDSP code RAM corruption (needed for PG2.1
884 * and newer; for older chips it's a NOP). Change FDSP clock
885 * settings so that it's muxed to the ATGP clock instead of
886 * its own clock.
887 */
888
889 ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
890 if (ret < 0)
891 goto out;
892
893 /* disable FDSP clock */
894 ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
895 MEM_FDSP_CLK_120_DISABLE);
896 if (ret < 0)
897 goto out;
898
899 /* set ATPG clock toward FDSP Code RAM rather than its own clock */
900 ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
901 MEM_FDSP_CODERAM_FUNC_CLK_SEL);
902 if (ret < 0)
903 goto out;
904
905 /* re-enable FDSP clock */
906 ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
907 MEM_FDSP_CLK_120_ENABLE);
Ido Yariv61343232012-06-18 15:50:21 +0300908
909out:
910 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300911}
912
Ido Yariveb96f842012-06-18 13:21:55 +0300913static int wl18xx_set_mac_and_phy(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300914{
Luciano Coelho23ee9bf2012-05-10 12:13:29 +0300915 struct wl18xx_priv *priv = wl->priv;
Arik Nemtsov45777c42012-07-05 17:30:58 +0300916 struct wl18xx_mac_and_phy_params *params;
Ido Yariveb96f842012-06-18 13:21:55 +0300917 int ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300918
Arik Nemtsov45777c42012-07-05 17:30:58 +0300919 params = kmemdup(&priv->conf.phy, sizeof(*params), GFP_KERNEL);
920 if (!params) {
921 ret = -ENOMEM;
922 goto out;
923 }
924
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300925 ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
926 if (ret < 0)
927 goto out;
928
Arik Nemtsov45777c42012-07-05 17:30:58 +0300929 ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, params,
930 sizeof(*params), false);
Ido Yariveb96f842012-06-18 13:21:55 +0300931
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300932out:
Arik Nemtsov45777c42012-07-05 17:30:58 +0300933 kfree(params);
Ido Yariveb96f842012-06-18 13:21:55 +0300934 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300935}
936
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300937static int wl18xx_enable_interrupts(struct wl1271 *wl)
Luciano Coelho46a1d512012-05-10 12:13:12 +0300938{
Ido Reisf5755fe2012-04-23 17:35:25 +0300939 u32 event_mask, intr_mask;
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300940 int ret;
Ido Reisf5755fe2012-04-23 17:35:25 +0300941
Luciano Coelhoe59bec12012-06-25 14:15:55 +0300942 event_mask = WL18XX_ACX_EVENTS_VECTOR;
943 intr_mask = WL18XX_INTR_MASK;
Ido Reisf5755fe2012-04-23 17:35:25 +0300944
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300945 ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask);
946 if (ret < 0)
947 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300948
949 wlcore_enable_interrupts(wl);
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300950
951 ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
952 WL1271_ACX_INTR_ALL & ~intr_mask);
Ido Yariva8311c82012-08-15 18:29:04 +0300953 if (ret < 0)
954 goto disable_interrupts;
955
956 return ret;
957
958disable_interrupts:
959 wlcore_disable_interrupts(wl);
Ido Yarivb0f0ad32012-06-20 00:48:23 +0300960
961out:
962 return ret;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300963}
964
965static int wl18xx_boot(struct wl1271 *wl)
966{
967 int ret;
968
969 ret = wl18xx_pre_boot(wl);
970 if (ret < 0)
971 goto out;
972
Ido Yariv61343232012-06-18 15:50:21 +0300973 ret = wl18xx_pre_upload(wl);
974 if (ret < 0)
975 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300976
977 ret = wlcore_boot_upload_firmware(wl);
978 if (ret < 0)
979 goto out;
980
Ido Yariveb96f842012-06-18 13:21:55 +0300981 ret = wl18xx_set_mac_and_phy(wl);
982 if (ret < 0)
983 goto out;
Luciano Coelho46a1d512012-05-10 12:13:12 +0300984
Eliad Pellerc50a2822012-11-22 18:06:19 +0200985 wl->event_mask = BSS_LOSS_EVENT_ID |
986 SCAN_COMPLETE_EVENT_ID |
987 RSSI_SNR_TRIGGER_0_EVENT_ID |
988 PERIODIC_SCAN_COMPLETE_EVENT_ID |
Eyal Shapira0b700782012-11-28 11:42:47 +0200989 PERIODIC_SCAN_REPORT_EVENT_ID |
Eliad Pellerc50a2822012-11-22 18:06:19 +0200990 DUMMY_PACKET_EVENT_ID |
991 PEER_REMOVE_COMPLETE_EVENT_ID |
992 BA_SESSION_RX_CONSTRAINT_EVENT_ID |
993 REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
994 INACTIVE_STA_EVENT_ID |
Victor Goldenshtein6b70e7e2012-11-25 18:26:59 +0200995 CHANNEL_SWITCH_COMPLETE_EVENT_ID |
Eliad Pellere93e15f2014-07-11 03:01:33 +0300996 DFS_CHANNELS_CONFIG_COMPLETE_EVENT |
997 SMART_CONFIG_SYNC_EVENT_ID |
998 SMART_CONFIG_DECODE_EVENT_ID;
999;
Eliad Pellerc50a2822012-11-22 18:06:19 +02001000
Eliad Peller71e996b2013-09-09 12:24:34 +03001001 wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID;
1002
Luciano Coelho46a1d512012-05-10 12:13:12 +03001003 ret = wlcore_boot_run_firmware(wl);
1004 if (ret < 0)
1005 goto out;
1006
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001007 ret = wl18xx_enable_interrupts(wl);
Luciano Coelho46a1d512012-05-10 12:13:12 +03001008
1009out:
1010 return ret;
1011}
1012
Ido Yariveb96f842012-06-18 13:21:55 +03001013static int wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
Luciano Coelho274c66c2012-05-10 12:13:13 +03001014 void *buf, size_t len)
1015{
1016 struct wl18xx_priv *priv = wl->priv;
1017
1018 memcpy(priv->cmd_buf, buf, len);
1019 memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len);
1020
Ido Yariveb96f842012-06-18 13:21:55 +03001021 return wlcore_write(wl, cmd_box_addr, priv->cmd_buf,
1022 WL18XX_CMD_MAX_SIZE, false);
Luciano Coelho274c66c2012-05-10 12:13:13 +03001023}
1024
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001025static int wl18xx_ack_event(struct wl1271 *wl)
Luciano Coelho274c66c2012-05-10 12:13:13 +03001026{
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001027 return wlcore_write_reg(wl, REG_INTERRUPT_TRIG,
1028 WL18XX_INTR_TRIG_EVENT_ACK);
Luciano Coelho274c66c2012-05-10 12:13:13 +03001029}
1030
Arik Nemtsov624845b2012-05-10 12:13:17 +03001031static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
1032{
1033 u32 blk_size = WL18XX_TX_HW_BLOCK_SIZE;
1034 return (len + blk_size - 1) / blk_size + spare_blks;
1035}
1036
Arik Nemtsovfb0f2e42012-05-10 12:13:18 +03001037static void
1038wl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
1039 u32 blks, u32 spare_blks)
1040{
1041 desc->wl18xx_mem.total_mem_blocks = blks;
Arik Nemtsovfb0f2e42012-05-10 12:13:18 +03001042}
1043
Arik Nemtsovd2361c52012-05-10 12:13:19 +03001044static void
1045wl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
1046 struct sk_buff *skb)
1047{
1048 desc->length = cpu_to_le16(skb->len);
1049
Ido Reis9fccc822012-05-13 14:53:40 +03001050 /* if only the last frame is to be padded, we unset this bit on Tx */
1051 if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME)
1052 desc->wl18xx_mem.ctrl = WL18XX_TX_CTRL_NOT_PADDED;
1053 else
1054 desc->wl18xx_mem.ctrl = 0;
1055
Arik Nemtsovd2361c52012-05-10 12:13:19 +03001056 wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
1057 "len: %d life: %d mem: %d", desc->hlid,
1058 le16_to_cpu(desc->length),
1059 le16_to_cpu(desc->life_time),
1060 desc->wl18xx_mem.total_mem_blocks);
1061}
1062
Arik Nemtsov9c809f82012-05-10 12:13:23 +03001063static enum wl_rx_buf_align
1064wl18xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
1065{
1066 if (rx_desc & RX_BUF_PADDED_PAYLOAD)
1067 return WLCORE_RX_BUF_PADDED;
1068
1069 return WLCORE_RX_BUF_ALIGNED;
1070}
1071
Arik Nemtsov30e2dd72012-05-10 12:13:24 +03001072static u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
1073 u32 data_len)
1074{
1075 struct wl1271_rx_descriptor *desc = rx_data;
1076
1077 /* invalid packet */
1078 if (data_len < sizeof(*desc))
1079 return 0;
1080
1081 return data_len - sizeof(*desc);
1082}
Arik Nemtsov9c809f82012-05-10 12:13:23 +03001083
Arik Nemtsov872b3452012-05-10 12:13:25 +03001084static void wl18xx_tx_immediate_completion(struct wl1271 *wl)
1085{
1086 wl18xx_tx_immediate_complete(wl);
1087}
1088
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001089static int wl18xx_set_host_cfg_bitmap(struct wl1271 *wl, u32 extra_mem_blk)
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001090{
1091 int ret;
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001092 u32 sdio_align_size = 0;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001093 u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE |
1094 HOST_IF_CFG_ADD_RX_ALIGNMENT;
Arik Nemtsovf2baf072012-05-10 12:13:46 +03001095
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001096 /* Enable Tx SDIO padding */
1097 if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) {
1098 host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
1099 sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
1100 }
1101
1102 /* Enable Rx SDIO padding */
1103 if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) {
1104 host_cfg_bitmap |= HOST_IF_CFG_RX_PAD_TO_SDIO_BLK;
1105 sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
1106 }
1107
1108 ret = wl18xx_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap,
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001109 sdio_align_size, extra_mem_blk,
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001110 WL18XX_HOST_IF_LEN_SIZE_FIELD);
1111 if (ret < 0)
1112 return ret;
1113
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001114 return 0;
1115}
1116
1117static int wl18xx_hw_init(struct wl1271 *wl)
1118{
1119 int ret;
1120 struct wl18xx_priv *priv = wl->priv;
1121
1122 /* (re)init private structures. Relevant on recovery as well. */
1123 priv->last_fw_rls_idx = 0;
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001124 priv->extra_spare_key_count = 0;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001125
1126 /* set the default amount of spare blocks in the bitmap */
1127 ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
1128 if (ret < 0)
1129 return ret;
1130
Luciano Coelho102165c2012-05-10 12:13:53 +03001131 if (checksum_param) {
1132 ret = wl18xx_acx_set_checksum_state(wl);
1133 if (ret != 0)
1134 return ret;
1135 }
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001136
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001137 return ret;
1138}
1139
Eliad Peller75fb4df2014-02-10 13:47:21 +02001140static void wl18xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
1141 struct wl_fw_status *fw_status)
1142{
1143 struct wl18xx_fw_status *int_fw_status = raw_fw_status;
1144
1145 fw_status->intr = le32_to_cpu(int_fw_status->intr);
1146 fw_status->fw_rx_counter = int_fw_status->fw_rx_counter;
1147 fw_status->drv_rx_counter = int_fw_status->drv_rx_counter;
1148 fw_status->tx_results_counter = int_fw_status->tx_results_counter;
1149 fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs;
1150
1151 fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime);
1152 fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap);
1153 fw_status->link_fast_bitmap =
1154 le32_to_cpu(int_fw_status->link_fast_bitmap);
1155 fw_status->total_released_blks =
1156 le32_to_cpu(int_fw_status->total_released_blks);
1157 fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total);
1158
1159 fw_status->counters.tx_released_pkts =
1160 int_fw_status->counters.tx_released_pkts;
1161 fw_status->counters.tx_lnk_free_pkts =
1162 int_fw_status->counters.tx_lnk_free_pkts;
1163 fw_status->counters.tx_voice_released_blks =
1164 int_fw_status->counters.tx_voice_released_blks;
1165 fw_status->counters.tx_last_rate =
1166 int_fw_status->counters.tx_last_rate;
1167
1168 fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
1169
1170 fw_status->priv = &int_fw_status->priv;
1171}
1172
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001173static void wl18xx_set_tx_desc_csum(struct wl1271 *wl,
1174 struct wl1271_tx_hw_descr *desc,
1175 struct sk_buff *skb)
1176{
1177 u32 ip_hdr_offset;
1178 struct iphdr *ip_hdr;
1179
Luciano Coelho102165c2012-05-10 12:13:53 +03001180 if (!checksum_param) {
1181 desc->wl18xx_checksum_data = 0;
1182 return;
1183 }
1184
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001185 if (skb->ip_summed != CHECKSUM_PARTIAL) {
1186 desc->wl18xx_checksum_data = 0;
1187 return;
1188 }
1189
1190 ip_hdr_offset = skb_network_header(skb) - skb_mac_header(skb);
1191 if (WARN_ON(ip_hdr_offset >= (1<<7))) {
1192 desc->wl18xx_checksum_data = 0;
1193 return;
1194 }
1195
1196 desc->wl18xx_checksum_data = ip_hdr_offset << 1;
1197
1198 /* FW is interested only in the LSB of the protocol TCP=0 UDP=1 */
1199 ip_hdr = (void *)skb_network_header(skb);
1200 desc->wl18xx_checksum_data |= (ip_hdr->protocol & 0x01);
1201}
1202
Arik Nemtsov169da042012-05-10 12:13:28 +03001203static void wl18xx_set_rx_csum(struct wl1271 *wl,
1204 struct wl1271_rx_descriptor *desc,
1205 struct sk_buff *skb)
1206{
1207 if (desc->status & WL18XX_RX_CHECKSUM_MASK)
1208 skb->ip_summed = CHECKSUM_UNNECESSARY;
1209}
1210
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001211static bool wl18xx_is_mimo_supported(struct wl1271 *wl)
1212{
1213 struct wl18xx_priv *priv = wl->priv;
1214
Arik Nemtsovc80daad2012-11-28 11:42:46 +02001215 /* only support MIMO with multiple antennas, and when SISO
1216 * is not forced through config
1217 */
1218 return (priv->conf.phy.number_of_assembled_ant2_4 >= 2) &&
1219 (priv->conf.ht.mode != HT_MODE_WIDE) &&
1220 (priv->conf.ht.mode != HT_MODE_SISO20);
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001221}
1222
Luciano Coelho7ae25da2012-05-10 12:14:03 +03001223/*
1224 * TODO: instead of having these two functions to get the rate mask,
1225 * we should modify the wlvif->rate_set instead
1226 */
Arik Nemtsovf13af342012-05-10 12:13:32 +03001227static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl,
1228 struct wl12xx_vif *wlvif)
1229{
1230 u32 hw_rate_set = wlvif->rate_set;
1231
1232 if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
1233 wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
1234 wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
1235 hw_rate_set |= CONF_TX_RATE_USE_WIDE_CHAN;
1236
1237 /* we don't support MIMO in wide-channel mode */
1238 hw_rate_set &= ~CONF_TX_MIMO_RATES;
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001239 } else if (wl18xx_is_mimo_supported(wl)) {
1240 wl1271_debug(DEBUG_ACX, "using MIMO channel rate mask");
1241 hw_rate_set |= CONF_TX_MIMO_RATES;
Arik Nemtsovf13af342012-05-10 12:13:32 +03001242 }
1243
1244 return hw_rate_set;
1245}
1246
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001247static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
1248 struct wl12xx_vif *wlvif)
1249{
Arik Nemtsov0344dcd2012-07-05 15:23:02 +03001250 if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
1251 wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
1252 wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
1253
1254 /* sanity check - we don't support this */
1255 if (WARN_ON(wlvif->band != IEEE80211_BAND_5GHZ))
1256 return 0;
1257
1258 return CONF_TX_RATE_USE_WIDE_CHAN;
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001259 } else if (wl18xx_is_mimo_supported(wl) &&
Arik Nemtsov0344dcd2012-07-05 15:23:02 +03001260 wlvif->band == IEEE80211_BAND_2GHZ) {
1261 wl1271_debug(DEBUG_ACX, "using MIMO rate mask");
1262 /*
1263 * we don't care about HT channel here - if a peer doesn't
1264 * support MIMO, we won't enable it in its rates
1265 */
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001266 return CONF_TX_MIMO_RATES;
Luciano Coelho174a7302012-05-10 12:14:13 +03001267 } else {
1268 return 0;
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001269 }
1270}
1271
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001272static const char *wl18xx_rdl_name(enum wl18xx_rdl_num rdl_num)
1273{
1274 switch (rdl_num) {
1275 case RDL_1_HP:
1276 return "183xH";
1277 case RDL_2_SP:
1278 return "183x or 180x";
1279 case RDL_3_HP:
1280 return "187xH";
1281 case RDL_4_SP:
1282 return "187x";
1283 case RDL_5_SP:
1284 return "RDL11 - Not Supported";
1285 case RDL_6_SP:
1286 return "180xD";
1287 case RDL_7_SP:
1288 return "RDL13 - Not Supported (1893Q)";
1289 case RDL_8_SP:
1290 return "18xxQ";
1291 case RDL_NONE:
1292 return "UNTRIMMED";
1293 default:
1294 return "UNKNOWN";
1295 }
1296}
1297
Ido Yariv61343232012-06-18 15:50:21 +03001298static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
Arik Nemtsov54956292012-05-10 12:13:44 +03001299{
1300 u32 fuse;
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001301 s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0, package_type = 0;
Ido Yariv61343232012-06-18 15:50:21 +03001302 int ret;
Arik Nemtsov54956292012-05-10 12:13:44 +03001303
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001304 ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
1305 if (ret < 0)
1306 goto out;
Arik Nemtsov54956292012-05-10 12:13:44 +03001307
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001308 ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
1309 if (ret < 0)
1310 goto out;
1311
1312 package_type = (fuse >> WL18XX_PACKAGE_TYPE_OFFSET) & 1;
1313
Ido Yariv61343232012-06-18 15:50:21 +03001314 ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
1315 if (ret < 0)
1316 goto out;
1317
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001318 pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
1319 rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
1320
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001321 if ((rom <= 0xE) && (package_type == WL18XX_PACKAGE_TYPE_WSP))
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001322 metal = (fuse & WL18XX_METAL_VER_MASK) >>
1323 WL18XX_METAL_VER_OFFSET;
1324 else
1325 metal = (fuse & WL18XX_NEW_METAL_VER_MASK) >>
1326 WL18XX_NEW_METAL_VER_OFFSET;
1327
1328 ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
1329 if (ret < 0)
1330 goto out;
1331
1332 rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET;
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001333
Victor Goldenshtein1f8a1892013-09-17 18:41:29 +03001334 wl1271_info("wl18xx HW: %s, PG %d.%d (ROM 0x%x)",
1335 wl18xx_rdl_name(rdl_ver), pg_ver, metal, rom);
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001336
Ido Yariv61343232012-06-18 15:50:21 +03001337 if (ver)
Victor Goldenshteinf9ae0852013-03-12 17:19:42 +02001338 *ver = pg_ver;
Arik Nemtsov54956292012-05-10 12:13:44 +03001339
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001340 ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
Arik Nemtsov54956292012-05-10 12:13:44 +03001341
Ido Yariv61343232012-06-18 15:50:21 +03001342out:
1343 return ret;
Arik Nemtsov54956292012-05-10 12:13:44 +03001344}
1345
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001346#define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin"
1347static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
Luciano Coelho23ee9bf2012-05-10 12:13:29 +03001348{
1349 struct wl18xx_priv *priv = wl->priv;
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001350 struct wlcore_conf_file *conf_file;
1351 const struct firmware *fw;
1352 int ret;
1353
1354 ret = request_firmware(&fw, WL18XX_CONF_FILE_NAME, dev);
1355 if (ret < 0) {
1356 wl1271_error("could not get configuration binary %s: %d",
1357 WL18XX_CONF_FILE_NAME, ret);
1358 goto out_fallback;
1359 }
1360
1361 if (fw->size != WL18XX_CONF_SIZE) {
Luciano Coelho41844072012-06-21 15:33:10 +03001362 wl1271_error("configuration binary file size is wrong, expected %zu got %zu",
1363 WL18XX_CONF_SIZE, fw->size);
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001364 ret = -EINVAL;
1365 goto out;
1366 }
1367
1368 conf_file = (struct wlcore_conf_file *) fw->data;
1369
1370 if (conf_file->header.magic != cpu_to_le32(WL18XX_CONF_MAGIC)) {
1371 wl1271_error("configuration binary file magic number mismatch, "
1372 "expected 0x%0x got 0x%0x", WL18XX_CONF_MAGIC,
1373 conf_file->header.magic);
1374 ret = -EINVAL;
1375 goto out;
1376 }
1377
1378 if (conf_file->header.version != cpu_to_le32(WL18XX_CONF_VERSION)) {
1379 wl1271_error("configuration binary file version not supported, "
1380 "expected 0x%08x got 0x%08x",
1381 WL18XX_CONF_VERSION, conf_file->header.version);
1382 ret = -EINVAL;
1383 goto out;
1384 }
1385
1386 memcpy(&wl->conf, &conf_file->core, sizeof(wl18xx_conf));
1387 memcpy(&priv->conf, &conf_file->priv, sizeof(priv->conf));
1388
1389 goto out;
1390
1391out_fallback:
1392 wl1271_warning("falling back to default config");
Luciano Coelho23ee9bf2012-05-10 12:13:29 +03001393
1394 /* apply driver default configuration */
1395 memcpy(&wl->conf, &wl18xx_conf, sizeof(wl18xx_conf));
Luciano Coelho23ee9bf2012-05-10 12:13:29 +03001396 /* apply default private configuration */
1397 memcpy(&priv->conf, &wl18xx_default_priv_conf, sizeof(priv->conf));
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001398
1399 /* For now we just fallback */
1400 return 0;
1401
1402out:
1403 release_firmware(fw);
1404 return ret;
Luciano Coelho23ee9bf2012-05-10 12:13:29 +03001405}
1406
Luciano Coelhobe42aee2012-05-10 12:13:50 +03001407static int wl18xx_plt_init(struct wl1271 *wl)
1408{
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001409 int ret;
1410
Yair Shapira16bc10c32012-07-11 18:48:05 +03001411 /* calibrator based auto/fem detect not supported for 18xx */
1412 if (wl->plt_mode == PLT_FEM_DETECT) {
1413 wl1271_error("wl18xx_plt_init: PLT FEM_DETECT not supported");
1414 return -EINVAL;
1415 }
1416
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001417 ret = wlcore_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT);
1418 if (ret < 0)
1419 return ret;
Luciano Coelhobe42aee2012-05-10 12:13:50 +03001420
1421 return wl->ops->boot(wl);
1422}
1423
Ido Yariv61343232012-06-18 15:50:21 +03001424static int wl18xx_get_mac(struct wl1271 *wl)
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001425{
1426 u32 mac1, mac2;
Ido Yariv61343232012-06-18 15:50:21 +03001427 int ret;
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001428
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001429 ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
1430 if (ret < 0)
1431 goto out;
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001432
Ido Yariv61343232012-06-18 15:50:21 +03001433 ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1, &mac1);
1434 if (ret < 0)
1435 goto out;
1436
1437 ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2, &mac2);
1438 if (ret < 0)
1439 goto out;
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001440
1441 /* these are the two parts of the BD_ADDR */
1442 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
1443 ((mac1 & 0xff000000) >> 24);
1444 wl->fuse_nic_addr = (mac1 & 0xffffff);
1445
Luciano Coelhobc2ab3b2013-05-08 12:54:56 +03001446 if (!wl->fuse_oui_addr && !wl->fuse_nic_addr) {
1447 u8 mac[ETH_ALEN];
1448
1449 eth_random_addr(mac);
1450
1451 wl->fuse_oui_addr = (mac[0] << 16) + (mac[1] << 8) + mac[2];
1452 wl->fuse_nic_addr = (mac[3] << 16) + (mac[4] << 8) + mac[5];
1453 wl1271_warning("MAC address from fuse not available, using random locally administered addresses.");
1454 }
1455
Ido Yarivb0f0ad32012-06-20 00:48:23 +03001456 ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
Ido Yariv61343232012-06-18 15:50:21 +03001457
1458out:
1459 return ret;
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001460}
1461
Luciano Coelho283e8c42012-05-10 12:14:11 +03001462static int wl18xx_handle_static_data(struct wl1271 *wl,
1463 struct wl1271_static_data *static_data)
1464{
1465 struct wl18xx_static_data_priv *static_data_priv =
1466 (struct wl18xx_static_data_priv *) static_data->priv;
1467
Yair Shapira1defbeb2012-08-07 17:38:21 +03001468 strncpy(wl->chip.phy_fw_ver_str, static_data_priv->phy_version,
1469 sizeof(wl->chip.phy_fw_ver_str));
1470
1471 /* make sure the string is NULL-terminated */
1472 wl->chip.phy_fw_ver_str[sizeof(wl->chip.phy_fw_ver_str) - 1] = '\0';
1473
Luciano Coelho283e8c42012-05-10 12:14:11 +03001474 wl1271_info("PHY firmware version: %s", static_data_priv->phy_version);
1475
1476 return 0;
1477}
1478
Arik Nemtsov32bb2c02012-05-18 07:46:37 +03001479static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
1480{
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001481 struct wl18xx_priv *priv = wl->priv;
1482
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001483 /* If we have keys requiring extra spare, indulge them */
1484 if (priv->extra_spare_key_count)
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001485 return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
1486
1487 return WL18XX_TX_HW_BLOCK_SPARE;
1488}
1489
1490static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
1491 struct ieee80211_vif *vif,
1492 struct ieee80211_sta *sta,
1493 struct ieee80211_key_conf *key_conf)
1494{
1495 struct wl18xx_priv *priv = wl->priv;
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001496 bool change_spare = false, special_enc;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001497 int ret;
1498
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001499 wl1271_debug(DEBUG_CRYPT, "extra spare keys before: %d",
1500 priv->extra_spare_key_count);
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001501
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001502 special_enc = key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
1503 key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001504
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001505 ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
1506 if (ret < 0)
1507 goto out;
1508
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001509 /*
1510 * when adding the first or removing the last GEM/TKIP key,
1511 * we have to adjust the number of spare blocks.
1512 */
1513 if (special_enc) {
1514 if (cmd == SET_KEY) {
1515 /* first key */
1516 change_spare = (priv->extra_spare_key_count == 0);
1517 priv->extra_spare_key_count++;
1518 } else if (cmd == DISABLE_KEY) {
1519 /* last key */
1520 change_spare = (priv->extra_spare_key_count == 1);
1521 priv->extra_spare_key_count--;
1522 }
1523 }
1524
1525 wl1271_debug(DEBUG_CRYPT, "extra spare keys after: %d",
1526 priv->extra_spare_key_count);
1527
1528 if (!change_spare)
1529 goto out;
1530
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001531 /* key is now set, change the spare blocks */
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001532 if (priv->extra_spare_key_count)
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001533 ret = wl18xx_set_host_cfg_bitmap(wl,
1534 WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
Arik Nemtsov2fd8a3b2012-11-28 11:42:48 +02001535 else
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001536 ret = wl18xx_set_host_cfg_bitmap(wl,
1537 WL18XX_TX_HW_BLOCK_SPARE);
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001538
1539out:
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001540 return ret;
Arik Nemtsov32bb2c02012-05-18 07:46:37 +03001541}
1542
Ido Reis9fccc822012-05-13 14:53:40 +03001543static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
1544 u32 buf_offset, u32 last_len)
1545{
1546 if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) {
1547 struct wl1271_tx_hw_descr *last_desc;
1548
1549 /* get the last TX HW descriptor written to the aggr buf */
1550 last_desc = (struct wl1271_tx_hw_descr *)(wl->aggr_buf +
1551 buf_offset - last_len);
1552
1553 /* the last frame is padded up to an SDIO block */
1554 last_desc->wl18xx_mem.ctrl &= ~WL18XX_TX_CTRL_NOT_PADDED;
1555 return ALIGN(buf_offset, WL12XX_BUS_BLOCK_SIZE);
1556 }
1557
1558 /* no modifications */
1559 return buf_offset;
1560}
1561
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001562static void wl18xx_sta_rc_update(struct wl1271 *wl,
Eliad Peller7d3b29e2014-12-29 08:24:03 +02001563 struct wl12xx_vif *wlvif)
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001564{
Eliad Peller7d3b29e2014-12-29 08:24:03 +02001565 bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40;
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001566
1567 wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
1568
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001569 /* sanity */
1570 if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
Eliad Peller7d3b29e2014-12-29 08:24:03 +02001571 return;
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001572
1573 /* ignore the change before association */
1574 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller7d3b29e2014-12-29 08:24:03 +02001575 return;
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001576
1577 /*
1578 * If we started out as wide, we can change the operation mode. If we
1579 * thought this was a 20mhz AP, we have to reconnect
1580 */
1581 if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS ||
1582 wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS)
1583 wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
1584 else
1585 ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001586}
1587
Eliad Peller530abe12012-11-28 11:42:31 +02001588static int wl18xx_set_peer_cap(struct wl1271 *wl,
1589 struct ieee80211_sta_ht_cap *ht_cap,
1590 bool allow_ht_operation,
1591 u32 rate_set, u8 hlid)
1592{
1593 return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation,
1594 rate_set, hlid);
1595}
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001596
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001597static bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
1598 struct wl1271_link *lnk)
1599{
1600 u8 thold;
1601 struct wl18xx_fw_status_priv *status_priv =
Eliad Peller75fb4df2014-02-10 13:47:21 +02001602 (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001603 unsigned long suspend_bitmap;
Eliad Peller9bccb8a2014-07-11 03:01:38 +03001604
1605 /* if we don't have the link map yet, assume they all low prio */
1606 if (!status_priv)
1607 return false;
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001608
1609 /* suspended links are never high priority */
Eliad Peller9bccb8a2014-07-11 03:01:38 +03001610 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001611 if (test_bit(hlid, &suspend_bitmap))
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001612 return false;
1613
1614 /* the priority thresholds are taken from FW */
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001615 if (test_bit(hlid, &wl->fw_fast_lnk_map) &&
1616 !test_bit(hlid, &wl->ap_fw_ps_map))
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001617 thold = status_priv->tx_fast_link_prio_threshold;
1618 else
1619 thold = status_priv->tx_slow_link_prio_threshold;
1620
1621 return lnk->allocated_pkts < thold;
1622}
1623
1624static bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
1625 struct wl1271_link *lnk)
1626{
1627 u8 thold;
1628 struct wl18xx_fw_status_priv *status_priv =
Eliad Peller75fb4df2014-02-10 13:47:21 +02001629 (struct wl18xx_fw_status_priv *)wl->fw_status->priv;
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001630 unsigned long suspend_bitmap;
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001631
Eliad Peller9bccb8a2014-07-11 03:01:38 +03001632 /* if we don't have the link map yet, assume they all low prio */
1633 if (!status_priv)
1634 return true;
1635
1636 suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001637 if (test_bit(hlid, &suspend_bitmap))
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001638 thold = status_priv->tx_suspend_threshold;
Eliad Peller5e74b3a2014-07-11 03:01:39 +03001639 else if (test_bit(hlid, &wl->fw_fast_lnk_map) &&
1640 !test_bit(hlid, &wl->ap_fw_ps_map))
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001641 thold = status_priv->tx_fast_stop_threshold;
1642 else
1643 thold = status_priv->tx_slow_stop_threshold;
1644
1645 return lnk->allocated_pkts < thold;
1646}
1647
Igal Chernobelskyc83cb802013-09-09 12:24:38 +03001648static u32 wl18xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
1649{
1650 return hwaddr & ~0x80000000;
1651}
1652
Ido Yariv3992eb22012-09-02 12:29:27 +03001653static int wl18xx_setup(struct wl1271 *wl);
1654
Luciano Coelho0cd65432012-05-10 12:13:11 +03001655static struct wlcore_ops wl18xx_ops = {
Ido Yariv3992eb22012-09-02 12:29:27 +03001656 .setup = wl18xx_setup,
Luciano Coelho46a1d512012-05-10 12:13:12 +03001657 .identify_chip = wl18xx_identify_chip,
1658 .boot = wl18xx_boot,
Luciano Coelhobe42aee2012-05-10 12:13:50 +03001659 .plt_init = wl18xx_plt_init,
Luciano Coelho274c66c2012-05-10 12:13:13 +03001660 .trigger_cmd = wl18xx_trigger_cmd,
1661 .ack_event = wl18xx_ack_event,
Eliad Pellerc50a2822012-11-22 18:06:19 +02001662 .wait_for_event = wl18xx_wait_for_event,
1663 .process_mailbox_events = wl18xx_process_mailbox_events,
Arik Nemtsov624845b2012-05-10 12:13:17 +03001664 .calc_tx_blocks = wl18xx_calc_tx_blocks,
Arik Nemtsovfb0f2e42012-05-10 12:13:18 +03001665 .set_tx_desc_blocks = wl18xx_set_tx_desc_blocks,
Arik Nemtsovd2361c52012-05-10 12:13:19 +03001666 .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len,
Arik Nemtsov9c809f82012-05-10 12:13:23 +03001667 .get_rx_buf_align = wl18xx_get_rx_buf_align,
Arik Nemtsov30e2dd72012-05-10 12:13:24 +03001668 .get_rx_packet_len = wl18xx_get_rx_packet_len,
Arik Nemtsov872b3452012-05-10 12:13:25 +03001669 .tx_immediate_compl = wl18xx_tx_immediate_completion,
1670 .tx_delayed_compl = NULL,
Luciano Coelhob8422dc2012-05-10 12:13:26 +03001671 .hw_init = wl18xx_hw_init,
Eliad Peller75fb4df2014-02-10 13:47:21 +02001672 .convert_fw_status = wl18xx_convert_fw_status,
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001673 .set_tx_desc_csum = wl18xx_set_tx_desc_csum,
Arik Nemtsov54956292012-05-10 12:13:44 +03001674 .get_pg_ver = wl18xx_get_pg_ver,
Arik Nemtsov169da042012-05-10 12:13:28 +03001675 .set_rx_csum = wl18xx_set_rx_csum,
Arik Nemtsovf13af342012-05-10 12:13:32 +03001676 .sta_get_ap_rate_mask = wl18xx_sta_get_ap_rate_mask,
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001677 .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
Luciano Coelhoa5114d92012-05-10 12:13:55 +03001678 .get_mac = wl18xx_get_mac,
Luciano Coelhoad62d812012-05-10 12:14:19 +03001679 .debugfs_init = wl18xx_debugfs_add_files,
Eliad Peller78e28062012-11-22 18:06:15 +02001680 .scan_start = wl18xx_scan_start,
1681 .scan_stop = wl18xx_scan_stop,
Eliad Peller78e28062012-11-22 18:06:15 +02001682 .sched_scan_start = wl18xx_sched_scan_start,
1683 .sched_scan_stop = wl18xx_scan_sched_scan_stop,
Luciano Coelho283e8c42012-05-10 12:14:11 +03001684 .handle_static_data = wl18xx_handle_static_data,
Arik Nemtsov32bb2c02012-05-18 07:46:37 +03001685 .get_spare_blocks = wl18xx_get_spare_blocks,
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001686 .set_key = wl18xx_set_key,
Eliad Pellerfcab1892012-11-22 18:06:18 +02001687 .channel_switch = wl18xx_cmd_channel_switch,
Ido Reis9fccc822012-05-13 14:53:40 +03001688 .pre_pkt_send = wl18xx_pre_pkt_send,
Arik Nemtsov5f9b6772012-11-26 18:05:41 +02001689 .sta_rc_update = wl18xx_sta_rc_update,
Eliad Peller530abe12012-11-28 11:42:31 +02001690 .set_peer_cap = wl18xx_set_peer_cap,
Igal Chernobelskyc83cb802013-09-09 12:24:38 +03001691 .convert_hwaddr = wl18xx_convert_hwaddr,
Arik Nemtsovf1626fd2012-11-28 11:42:40 +02001692 .lnk_high_prio = wl18xx_lnk_high_prio,
1693 .lnk_low_prio = wl18xx_lnk_low_prio,
Eliad Pellerccb1df92014-07-11 03:01:31 +03001694 .smart_config_start = wl18xx_cmd_smart_config_start,
1695 .smart_config_stop = wl18xx_cmd_smart_config_stop,
1696 .smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
Ram Amrani6d5a7482014-12-29 08:24:04 +02001697 .interrupt_notify = wl18xx_acx_interrupt_notify_config,
1698 .rx_ba_filter = wl18xx_acx_rx_ba_filter,
Luciano Coelho0cd65432012-05-10 12:13:11 +03001699};
1700
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001701/* HT cap appropriate for wide channels in 2Ghz */
1702static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
Arik Nemtsov0e0f5a32012-05-10 12:13:35 +03001703 .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
Eliad Peller0330ee12012-11-27 08:44:49 +02001704 IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40 |
1705 IEEE80211_HT_CAP_GRN_FLD,
Arik Nemtsov0e0f5a32012-05-10 12:13:35 +03001706 .ht_supported = true,
1707 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
1708 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
1709 .mcs = {
1710 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
1711 .rx_highest = cpu_to_le16(150),
1712 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1713 },
1714};
1715
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001716/* HT cap appropriate for wide channels in 5Ghz */
1717static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
1718 .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
Eliad Peller0330ee12012-11-27 08:44:49 +02001719 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
1720 IEEE80211_HT_CAP_GRN_FLD,
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001721 .ht_supported = true,
1722 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
1723 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
1724 .mcs = {
1725 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
1726 .rx_highest = cpu_to_le16(150),
1727 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1728 },
1729};
1730
Luciano Coelho83342712012-05-10 12:14:15 +03001731/* HT cap appropriate for SISO 20 */
1732static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
Eliad Peller0330ee12012-11-27 08:44:49 +02001733 .cap = IEEE80211_HT_CAP_SGI_20 |
1734 IEEE80211_HT_CAP_GRN_FLD,
Luciano Coelho83342712012-05-10 12:14:15 +03001735 .ht_supported = true,
1736 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
1737 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
1738 .mcs = {
1739 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
1740 .rx_highest = cpu_to_le16(72),
1741 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1742 },
1743};
1744
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +03001745/* HT cap appropriate for MIMO rates in 20mhz channel */
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03001746static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
Eliad Peller0330ee12012-11-27 08:44:49 +02001747 .cap = IEEE80211_HT_CAP_SGI_20 |
1748 IEEE80211_HT_CAP_GRN_FLD,
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +03001749 .ht_supported = true,
1750 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
1751 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
1752 .mcs = {
1753 .rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, },
1754 .rx_highest = cpu_to_le16(144),
1755 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1756 },
1757};
1758
Eliad Pellerabf0b242014-02-10 13:47:24 +02001759static const struct ieee80211_iface_limit wl18xx_iface_limits[] = {
1760 {
1761 .max = 3,
1762 .types = BIT(NL80211_IFTYPE_STATION),
1763 },
1764 {
1765 .max = 1,
1766 .types = BIT(NL80211_IFTYPE_AP) |
1767 BIT(NL80211_IFTYPE_P2P_GO) |
1768 BIT(NL80211_IFTYPE_P2P_CLIENT),
1769 },
1770};
1771
1772static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {
1773 {
1774 .max = 2,
1775 .types = BIT(NL80211_IFTYPE_AP),
1776 },
1777};
1778
1779static const struct ieee80211_iface_combination
1780wl18xx_iface_combinations[] = {
1781 {
1782 .max_interfaces = 3,
1783 .limits = wl18xx_iface_limits,
1784 .n_limits = ARRAY_SIZE(wl18xx_iface_limits),
1785 .num_different_channels = 2,
1786 },
1787 {
1788 .max_interfaces = 2,
1789 .limits = wl18xx_iface_ap_limits,
1790 .n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits),
1791 .num_different_channels = 1,
1792 }
1793};
1794
Ido Yariv3992eb22012-09-02 12:29:27 +03001795static int wl18xx_setup(struct wl1271 *wl)
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001796{
Ido Yariv3992eb22012-09-02 12:29:27 +03001797 struct wl18xx_priv *priv = wl->priv;
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001798 int ret;
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001799
Eliad Pellerda08fdf2014-02-10 13:47:22 +02001800 BUILD_BUG_ON(WL18XX_MAX_LINKS > WLCORE_MAX_LINKS);
Eliad Peller32f0fd52014-02-10 13:47:23 +02001801 BUILD_BUG_ON(WL18XX_MAX_AP_STATIONS > WL18XX_MAX_LINKS);
Eliad Pellerda08fdf2014-02-10 13:47:22 +02001802
Luciano Coelho5d4a9fa2012-05-10 12:13:10 +03001803 wl->rtable = wl18xx_rtable;
Igal Chernobelskyf1c434d2012-07-31 14:48:46 +03001804 wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
Yair Shapirac91ec5f2012-11-28 11:42:39 +02001805 wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
Eliad Pellerda08fdf2014-02-10 13:47:22 +02001806 wl->num_links = WL18XX_MAX_LINKS;
Eliad Peller32f0fd52014-02-10 13:47:23 +02001807 wl->max_ap_stations = WL18XX_MAX_AP_STATIONS;
Eliad Pellerabf0b242014-02-10 13:47:24 +02001808 wl->iface_combinations = wl18xx_iface_combinations;
1809 wl->n_iface_combinations = ARRAY_SIZE(wl18xx_iface_combinations);
Arik Nemtsovf4afbed2012-08-02 20:37:21 +03001810 wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
Arik Nemtsovf648eab2012-05-10 12:13:20 +03001811 wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
1812 wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
1813 wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
Eliad Peller75fb4df2014-02-10 13:47:21 +02001814 wl->fw_status_len = sizeof(struct wl18xx_fw_status);
Arik Nemtsov1fab39d2012-05-10 12:13:21 +03001815 wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv);
Luciano Coelho8c0ea102012-05-10 12:14:09 +03001816 wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
Luciano Coelho283e8c42012-05-10 12:14:11 +03001817 wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
Luciano Coelho83342712012-05-10 12:14:15 +03001818
Arik Nemtsov09aad142012-06-10 22:57:30 +03001819 if (num_rx_desc_param != -1)
1820 wl->num_rx_desc = num_rx_desc_param;
1821
Ido Yariv3992eb22012-09-02 12:29:27 +03001822 ret = wl18xx_conf_init(wl, wl->dev);
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001823 if (ret < 0)
Ido Yariv3992eb22012-09-02 12:29:27 +03001824 return ret;
Luciano Coelho776f0302012-05-10 12:13:58 +03001825
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001826 /* If the module param is set, update it in conf */
1827 if (board_type_param) {
1828 if (!strcmp(board_type_param, "fpga")) {
1829 priv->conf.phy.board_type = BOARD_TYPE_FPGA_18XX;
1830 } else if (!strcmp(board_type_param, "hdk")) {
1831 priv->conf.phy.board_type = BOARD_TYPE_HDK_18XX;
1832 } else if (!strcmp(board_type_param, "dvp")) {
1833 priv->conf.phy.board_type = BOARD_TYPE_DVP_18XX;
1834 } else if (!strcmp(board_type_param, "evb")) {
1835 priv->conf.phy.board_type = BOARD_TYPE_EVB_18XX;
1836 } else if (!strcmp(board_type_param, "com8")) {
1837 priv->conf.phy.board_type = BOARD_TYPE_COM8_18XX;
1838 } else {
1839 wl1271_error("invalid board type '%s'",
1840 board_type_param);
Ido Yariv3992eb22012-09-02 12:29:27 +03001841 return -EINVAL;
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001842 }
1843 }
1844
Ido Reise1c497c2012-07-13 00:12:08 +03001845 if (priv->conf.phy.board_type >= NUM_BOARD_TYPES) {
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001846 wl1271_error("invalid board type '%d'",
1847 priv->conf.phy.board_type);
Ido Yariv3992eb22012-09-02 12:29:27 +03001848 return -EINVAL;
Luciano Coelhoa9c130d2012-05-10 12:13:37 +03001849 }
1850
Arik Nemtsov17d97712012-05-29 12:44:12 +03001851 if (low_band_component_param != -1)
1852 priv->conf.phy.low_band_component = low_band_component_param;
1853 if (low_band_component_type_param != -1)
Luciano Coelho858403a2012-05-10 12:14:17 +03001854 priv->conf.phy.low_band_component_type =
Arik Nemtsov17d97712012-05-29 12:44:12 +03001855 low_band_component_type_param;
1856 if (high_band_component_param != -1)
1857 priv->conf.phy.high_band_component = high_band_component_param;
1858 if (high_band_component_type_param != -1)
Luciano Coelho858403a2012-05-10 12:14:17 +03001859 priv->conf.phy.high_band_component_type =
Arik Nemtsov17d97712012-05-29 12:44:12 +03001860 high_band_component_type_param;
1861 if (pwr_limit_reference_11_abg_param != -1)
Luciano Coelho7b03c302012-05-10 12:14:18 +03001862 priv->conf.phy.pwr_limit_reference_11_abg =
Arik Nemtsov17d97712012-05-29 12:44:12 +03001863 pwr_limit_reference_11_abg_param;
1864 if (n_antennas_2_param != -1)
1865 priv->conf.phy.number_of_assembled_ant2_4 = n_antennas_2_param;
1866 if (n_antennas_5_param != -1)
1867 priv->conf.phy.number_of_assembled_ant5 = n_antennas_5_param;
1868 if (dc2dc_param != -1)
1869 priv->conf.phy.external_pa_dc2dc = dc2dc_param;
Luciano Coelho7b03c302012-05-10 12:14:18 +03001870
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001871 if (ht_mode_param) {
1872 if (!strcmp(ht_mode_param, "default"))
1873 priv->conf.ht.mode = HT_MODE_DEFAULT;
1874 else if (!strcmp(ht_mode_param, "wide"))
1875 priv->conf.ht.mode = HT_MODE_WIDE;
1876 else if (!strcmp(ht_mode_param, "siso20"))
1877 priv->conf.ht.mode = HT_MODE_SISO20;
1878 else {
1879 wl1271_error("invalid ht_mode '%s'", ht_mode_param);
Ido Yariv3992eb22012-09-02 12:29:27 +03001880 return -EINVAL;
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001881 }
1882 }
1883
1884 if (priv->conf.ht.mode == HT_MODE_DEFAULT) {
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001885 /*
1886 * Only support mimo with multiple antennas. Fall back to
Arik Nemtsov8c5dab12012-08-15 19:11:43 +03001887 * siso40.
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001888 */
Arik Nemtsovcc31a3c2012-07-12 12:29:46 +03001889 if (wl18xx_is_mimo_supported(wl))
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001890 wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
1891 &wl18xx_mimo_ht_cap_2ghz);
1892 else
1893 wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
Arik Nemtsov8c5dab12012-08-15 19:11:43 +03001894 &wl18xx_siso40_ht_cap_2ghz);
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001895
1896 /* 5Ghz is always wide */
1897 wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001898 &wl18xx_siso40_ht_cap_5ghz);
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001899 } else if (priv->conf.ht.mode == HT_MODE_WIDE) {
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001900 wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001901 &wl18xx_siso40_ht_cap_2ghz);
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001902 wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
Arik Nemtsov93fb19b2012-06-13 19:09:26 +03001903 &wl18xx_siso40_ht_cap_5ghz);
Yair Shapirac68cc0f2012-07-05 15:11:30 +00001904 } else if (priv->conf.ht.mode == HT_MODE_SISO20) {
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001905 wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ,
1906 &wl18xx_siso20_ht_cap);
1907 wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ,
1908 &wl18xx_siso20_ht_cap);
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001909 }
1910
Luciano Coelho102165c2012-05-10 12:13:53 +03001911 if (!checksum_param) {
1912 wl18xx_ops.set_rx_csum = NULL;
1913 wl18xx_ops.init_vif = NULL;
1914 }
1915
Yair Shapirae166de52012-08-05 16:51:16 +03001916 /* Enable 11a Band only if we have 5G antennas */
1917 wl->enable_11a = (priv->conf.phy.number_of_assembled_ant5 != 0);
Luciano Coelho1ddbc7d2012-05-10 12:13:56 +03001918
Ido Yariv3992eb22012-09-02 12:29:27 +03001919 return 0;
1920}
1921
Bill Pembertonb74324d2012-12-03 09:56:42 -05001922static int wl18xx_probe(struct platform_device *pdev)
Ido Yariv3992eb22012-09-02 12:29:27 +03001923{
1924 struct wl1271 *wl;
1925 struct ieee80211_hw *hw;
1926 int ret;
1927
1928 hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv),
Eliad Pellerc50a2822012-11-22 18:06:19 +02001929 WL18XX_AGGR_BUFFER_SIZE,
1930 sizeof(struct wl18xx_event_mailbox));
Ido Yariv3992eb22012-09-02 12:29:27 +03001931 if (IS_ERR(hw)) {
1932 wl1271_error("can't allocate hw");
1933 ret = PTR_ERR(hw);
1934 goto out;
1935 }
1936
1937 wl = hw->priv;
1938 wl->ops = &wl18xx_ops;
1939 wl->ptable = wl18xx_ptable;
1940 ret = wlcore_probe(wl, pdev);
1941 if (ret)
1942 goto out_free;
1943
1944 return ret;
Luciano Coelho83342712012-05-10 12:14:15 +03001945
1946out_free:
1947 wlcore_free_hw(wl);
Luciano Coelho640dfb9b2012-06-07 23:39:28 +03001948out:
1949 return ret;
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001950}
1951
Bill Pembertonb74324d2012-12-03 09:56:42 -05001952static const struct platform_device_id wl18xx_id_table[] = {
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001953 { "wl18xx", 0 },
1954 { } /* Terminating Entry */
1955};
1956MODULE_DEVICE_TABLE(platform, wl18xx_id_table);
1957
1958static struct platform_driver wl18xx_driver = {
1959 .probe = wl18xx_probe,
Bill Pembertonb74324d2012-12-03 09:56:42 -05001960 .remove = wlcore_remove,
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001961 .id_table = wl18xx_id_table,
1962 .driver = {
1963 .name = "wl18xx_driver",
Luciano Coelho9a1a6992012-05-10 12:13:06 +03001964 }
1965};
1966
Devendra Naga77e7b302012-08-29 23:03:01 +05301967module_platform_driver(wl18xx_driver);
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +03001968module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR);
Arik Nemtsovfa2adfc2012-06-13 19:09:25 +03001969MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20");
Arik Nemtsov3a8ddb62012-05-10 12:13:36 +03001970
Luciano Coelhoa9c130d2012-05-10 12:13:37 +03001971module_param_named(board_type, board_type_param, charp, S_IRUSR);
Luciano Coelho4b9d2362012-05-10 12:13:59 +03001972MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
1973 "dvp");
Luciano Coelhoa9c130d2012-05-10 12:13:37 +03001974
Luciano Coelho102165c2012-05-10 12:13:53 +03001975module_param_named(checksum, checksum_param, bool, S_IRUSR);
Assaf Azulay3d62eb52012-05-10 12:14:23 +03001976MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)");
Luciano Coelho102165c2012-05-10 12:13:53 +03001977
Arik Nemtsov17d97712012-05-29 12:44:12 +03001978module_param_named(dc2dc, dc2dc_param, int, S_IRUSR);
1979MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)");
1980
1981module_param_named(n_antennas_2, n_antennas_2_param, int, S_IRUSR);
1982MODULE_PARM_DESC(n_antennas_2,
1983 "Number of installed 2.4GHz antennas: 1 (default) or 2");
1984
1985module_param_named(n_antennas_5, n_antennas_5_param, int, S_IRUSR);
1986MODULE_PARM_DESC(n_antennas_5,
1987 "Number of installed 5GHz antennas: 1 (default) or 2");
1988
1989module_param_named(low_band_component, low_band_component_param, int,
1990 S_IRUSR);
Luciano Coelho858403a2012-05-10 12:14:17 +03001991MODULE_PARM_DESC(low_band_component, "Low band component: u8 "
1992 "(default is 0x01)");
1993
Arik Nemtsov17d97712012-05-29 12:44:12 +03001994module_param_named(low_band_component_type, low_band_component_type_param,
1995 int, S_IRUSR);
Luciano Coelho858403a2012-05-10 12:14:17 +03001996MODULE_PARM_DESC(low_band_component_type, "Low band component type: u8 "
1997 "(default is 0x05 or 0x06 depending on the board_type)");
1998
Arik Nemtsov17d97712012-05-29 12:44:12 +03001999module_param_named(high_band_component, high_band_component_param, int,
2000 S_IRUSR);
Luciano Coelho858403a2012-05-10 12:14:17 +03002001MODULE_PARM_DESC(high_band_component, "High band component: u8, "
2002 "(default is 0x01)");
2003
Arik Nemtsov17d97712012-05-29 12:44:12 +03002004module_param_named(high_band_component_type, high_band_component_type_param,
2005 int, S_IRUSR);
Luciano Coelho858403a2012-05-10 12:14:17 +03002006MODULE_PARM_DESC(high_band_component_type, "High band component type: u8 "
2007 "(default is 0x09)");
2008
Arik Nemtsov17d97712012-05-29 12:44:12 +03002009module_param_named(pwr_limit_reference_11_abg,
2010 pwr_limit_reference_11_abg_param, int, S_IRUSR);
Luciano Coelho7b03c302012-05-10 12:14:18 +03002011MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
2012 "(default is 0xc8)");
2013
Arik Nemtsov09aad142012-06-10 22:57:30 +03002014module_param_named(num_rx_desc,
2015 num_rx_desc_param, int, S_IRUSR);
2016MODULE_PARM_DESC(num_rx_desc_param,
2017 "Number of Rx descriptors: u8 (default is 32)");
2018
Luciano Coelho9a1a6992012-05-10 12:13:06 +03002019MODULE_LICENSE("GPL v2");
2020MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Luciano Coelho0cd65432012-05-10 12:13:11 +03002021MODULE_FIRMWARE(WL18XX_FW_NAME);