diff options
Diffstat (limited to 'drivers/net/wireless/ti/wl18xx/main.c')
-rw-r--r-- | drivers/net/wireless/ti/wl18xx/main.c | 1463 |
1 files changed, 1463 insertions, 0 deletions
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c new file mode 100644 index 000000000000..ed9c3650e08a --- /dev/null +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
@@ -0,0 +1,1463 @@ | |||
1 | /* | ||
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> | ||
24 | #include <linux/ip.h> | ||
25 | #include <linux/firmware.h> | ||
26 | |||
27 | #include "../wlcore/wlcore.h" | ||
28 | #include "../wlcore/debug.h" | ||
29 | #include "../wlcore/io.h" | ||
30 | #include "../wlcore/acx.h" | ||
31 | #include "../wlcore/tx.h" | ||
32 | #include "../wlcore/rx.h" | ||
33 | #include "../wlcore/io.h" | ||
34 | #include "../wlcore/boot.h" | ||
35 | |||
36 | #include "reg.h" | ||
37 | #include "conf.h" | ||
38 | #include "acx.h" | ||
39 | #include "tx.h" | ||
40 | #include "wl18xx.h" | ||
41 | #include "io.h" | ||
42 | #include "debugfs.h" | ||
43 | |||
44 | #define WL18XX_RX_CHECKSUM_MASK 0x40 | ||
45 | |||
46 | static char *ht_mode_param = "wide"; | ||
47 | static char *board_type_param = "hdk"; | ||
48 | static bool checksum_param = false; | ||
49 | static bool enable_11a_param = true; | ||
50 | |||
51 | /* phy paramters */ | ||
52 | static int dc2dc_param = -1; | ||
53 | static int n_antennas_2_param = -1; | ||
54 | static int n_antennas_5_param = -1; | ||
55 | static int low_band_component_param = -1; | ||
56 | static int low_band_component_type_param = -1; | ||
57 | static int high_band_component_param = -1; | ||
58 | static int high_band_component_type_param = -1; | ||
59 | static int pwr_limit_reference_11_abg_param = -1; | ||
60 | |||
61 | static const u8 wl18xx_rate_to_idx_2ghz[] = { | ||
62 | /* MCS rates are used only with 11n */ | ||
63 | 15, /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */ | ||
64 | 14, /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */ | ||
65 | 13, /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */ | ||
66 | 12, /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */ | ||
67 | 11, /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */ | ||
68 | 10, /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */ | ||
69 | 9, /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */ | ||
70 | 8, /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */ | ||
71 | 7, /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */ | ||
72 | 6, /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */ | ||
73 | 5, /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */ | ||
74 | 4, /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */ | ||
75 | 3, /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */ | ||
76 | 2, /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */ | ||
77 | 1, /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */ | ||
78 | 0, /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */ | ||
79 | |||
80 | 11, /* WL18XX_CONF_HW_RXTX_RATE_54 */ | ||
81 | 10, /* WL18XX_CONF_HW_RXTX_RATE_48 */ | ||
82 | 9, /* WL18XX_CONF_HW_RXTX_RATE_36 */ | ||
83 | 8, /* WL18XX_CONF_HW_RXTX_RATE_24 */ | ||
84 | |||
85 | /* TI-specific rate */ | ||
86 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22 */ | ||
87 | |||
88 | 7, /* WL18XX_CONF_HW_RXTX_RATE_18 */ | ||
89 | 6, /* WL18XX_CONF_HW_RXTX_RATE_12 */ | ||
90 | 3, /* WL18XX_CONF_HW_RXTX_RATE_11 */ | ||
91 | 5, /* WL18XX_CONF_HW_RXTX_RATE_9 */ | ||
92 | 4, /* WL18XX_CONF_HW_RXTX_RATE_6 */ | ||
93 | 2, /* WL18XX_CONF_HW_RXTX_RATE_5_5 */ | ||
94 | 1, /* WL18XX_CONF_HW_RXTX_RATE_2 */ | ||
95 | 0 /* WL18XX_CONF_HW_RXTX_RATE_1 */ | ||
96 | }; | ||
97 | |||
98 | static const u8 wl18xx_rate_to_idx_5ghz[] = { | ||
99 | /* MCS rates are used only with 11n */ | ||
100 | 15, /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */ | ||
101 | 14, /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */ | ||
102 | 13, /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */ | ||
103 | 12, /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */ | ||
104 | 11, /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */ | ||
105 | 10, /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */ | ||
106 | 9, /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */ | ||
107 | 8, /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */ | ||
108 | 7, /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */ | ||
109 | 6, /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */ | ||
110 | 5, /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */ | ||
111 | 4, /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */ | ||
112 | 3, /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */ | ||
113 | 2, /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */ | ||
114 | 1, /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */ | ||
115 | 0, /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */ | ||
116 | |||
117 | 7, /* WL18XX_CONF_HW_RXTX_RATE_54 */ | ||
118 | 6, /* WL18XX_CONF_HW_RXTX_RATE_48 */ | ||
119 | 5, /* WL18XX_CONF_HW_RXTX_RATE_36 */ | ||
120 | 4, /* WL18XX_CONF_HW_RXTX_RATE_24 */ | ||
121 | |||
122 | /* TI-specific rate */ | ||
123 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22 */ | ||
124 | |||
125 | 3, /* WL18XX_CONF_HW_RXTX_RATE_18 */ | ||
126 | 2, /* WL18XX_CONF_HW_RXTX_RATE_12 */ | ||
127 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_11 */ | ||
128 | 1, /* WL18XX_CONF_HW_RXTX_RATE_9 */ | ||
129 | 0, /* WL18XX_CONF_HW_RXTX_RATE_6 */ | ||
130 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_5_5 */ | ||
131 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_2 */ | ||
132 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_1 */ | ||
133 | }; | ||
134 | |||
135 | static const u8 *wl18xx_band_rate_to_idx[] = { | ||
136 | [IEEE80211_BAND_2GHZ] = wl18xx_rate_to_idx_2ghz, | ||
137 | [IEEE80211_BAND_5GHZ] = wl18xx_rate_to_idx_5ghz | ||
138 | }; | ||
139 | |||
140 | enum wl18xx_hw_rates { | ||
141 | WL18XX_CONF_HW_RXTX_RATE_MCS15 = 0, | ||
142 | WL18XX_CONF_HW_RXTX_RATE_MCS14, | ||
143 | WL18XX_CONF_HW_RXTX_RATE_MCS13, | ||
144 | WL18XX_CONF_HW_RXTX_RATE_MCS12, | ||
145 | WL18XX_CONF_HW_RXTX_RATE_MCS11, | ||
146 | WL18XX_CONF_HW_RXTX_RATE_MCS10, | ||
147 | WL18XX_CONF_HW_RXTX_RATE_MCS9, | ||
148 | WL18XX_CONF_HW_RXTX_RATE_MCS8, | ||
149 | WL18XX_CONF_HW_RXTX_RATE_MCS7, | ||
150 | WL18XX_CONF_HW_RXTX_RATE_MCS6, | ||
151 | WL18XX_CONF_HW_RXTX_RATE_MCS5, | ||
152 | WL18XX_CONF_HW_RXTX_RATE_MCS4, | ||
153 | WL18XX_CONF_HW_RXTX_RATE_MCS3, | ||
154 | WL18XX_CONF_HW_RXTX_RATE_MCS2, | ||
155 | WL18XX_CONF_HW_RXTX_RATE_MCS1, | ||
156 | WL18XX_CONF_HW_RXTX_RATE_MCS0, | ||
157 | WL18XX_CONF_HW_RXTX_RATE_54, | ||
158 | WL18XX_CONF_HW_RXTX_RATE_48, | ||
159 | WL18XX_CONF_HW_RXTX_RATE_36, | ||
160 | WL18XX_CONF_HW_RXTX_RATE_24, | ||
161 | WL18XX_CONF_HW_RXTX_RATE_22, | ||
162 | WL18XX_CONF_HW_RXTX_RATE_18, | ||
163 | WL18XX_CONF_HW_RXTX_RATE_12, | ||
164 | WL18XX_CONF_HW_RXTX_RATE_11, | ||
165 | WL18XX_CONF_HW_RXTX_RATE_9, | ||
166 | WL18XX_CONF_HW_RXTX_RATE_6, | ||
167 | WL18XX_CONF_HW_RXTX_RATE_5_5, | ||
168 | WL18XX_CONF_HW_RXTX_RATE_2, | ||
169 | WL18XX_CONF_HW_RXTX_RATE_1, | ||
170 | WL18XX_CONF_HW_RXTX_RATE_MAX, | ||
171 | }; | ||
172 | |||
173 | static struct wlcore_conf wl18xx_conf = { | ||
174 | .sg = { | ||
175 | .params = { | ||
176 | [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, | ||
177 | [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, | ||
178 | [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, | ||
179 | [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, | ||
180 | [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, | ||
181 | [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, | ||
182 | [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, | ||
183 | [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, | ||
184 | [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, | ||
185 | [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, | ||
186 | [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, | ||
187 | [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, | ||
188 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, | ||
189 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, | ||
190 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, | ||
191 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, | ||
192 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, | ||
193 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, | ||
194 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, | ||
195 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, | ||
196 | [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, | ||
197 | [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, | ||
198 | [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, | ||
199 | [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, | ||
200 | [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, | ||
201 | [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, | ||
202 | /* active scan params */ | ||
203 | [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, | ||
204 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, | ||
205 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, | ||
206 | /* passive scan params */ | ||
207 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, | ||
208 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, | ||
209 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, | ||
210 | /* passive scan in dual antenna params */ | ||
211 | [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, | ||
212 | [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, | ||
213 | [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, | ||
214 | /* general params */ | ||
215 | [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, | ||
216 | [CONF_SG_ANTENNA_CONFIGURATION] = 0, | ||
217 | [CONF_SG_BEACON_MISS_PERCENT] = 60, | ||
218 | [CONF_SG_DHCP_TIME] = 5000, | ||
219 | [CONF_SG_RXT] = 1200, | ||
220 | [CONF_SG_TXT] = 1000, | ||
221 | [CONF_SG_ADAPTIVE_RXT_TXT] = 1, | ||
222 | [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, | ||
223 | [CONF_SG_HV3_MAX_SERVED] = 6, | ||
224 | [CONF_SG_PS_POLL_TIMEOUT] = 10, | ||
225 | [CONF_SG_UPSD_TIMEOUT] = 10, | ||
226 | [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, | ||
227 | [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, | ||
228 | [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, | ||
229 | /* AP params */ | ||
230 | [CONF_AP_BEACON_MISS_TX] = 3, | ||
231 | [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, | ||
232 | [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, | ||
233 | [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, | ||
234 | [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, | ||
235 | [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, | ||
236 | /* CTS Diluting params */ | ||
237 | [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, | ||
238 | [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, | ||
239 | }, | ||
240 | .state = CONF_SG_PROTECTIVE, | ||
241 | }, | ||
242 | .rx = { | ||
243 | .rx_msdu_life_time = 512000, | ||
244 | .packet_detection_threshold = 0, | ||
245 | .ps_poll_timeout = 15, | ||
246 | .upsd_timeout = 15, | ||
247 | .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, | ||
248 | .rx_cca_threshold = 0, | ||
249 | .irq_blk_threshold = 0xFFFF, | ||
250 | .irq_pkt_threshold = 0, | ||
251 | .irq_timeout = 600, | ||
252 | .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, | ||
253 | }, | ||
254 | .tx = { | ||
255 | .tx_energy_detection = 0, | ||
256 | .sta_rc_conf = { | ||
257 | .enabled_rates = 0, | ||
258 | .short_retry_limit = 10, | ||
259 | .long_retry_limit = 10, | ||
260 | .aflags = 0, | ||
261 | }, | ||
262 | .ac_conf_count = 4, | ||
263 | .ac_conf = { | ||
264 | [CONF_TX_AC_BE] = { | ||
265 | .ac = CONF_TX_AC_BE, | ||
266 | .cw_min = 15, | ||
267 | .cw_max = 63, | ||
268 | .aifsn = 3, | ||
269 | .tx_op_limit = 0, | ||
270 | }, | ||
271 | [CONF_TX_AC_BK] = { | ||
272 | .ac = CONF_TX_AC_BK, | ||
273 | .cw_min = 15, | ||
274 | .cw_max = 63, | ||
275 | .aifsn = 7, | ||
276 | .tx_op_limit = 0, | ||
277 | }, | ||
278 | [CONF_TX_AC_VI] = { | ||
279 | .ac = CONF_TX_AC_VI, | ||
280 | .cw_min = 15, | ||
281 | .cw_max = 63, | ||
282 | .aifsn = CONF_TX_AIFS_PIFS, | ||
283 | .tx_op_limit = 3008, | ||
284 | }, | ||
285 | [CONF_TX_AC_VO] = { | ||
286 | .ac = CONF_TX_AC_VO, | ||
287 | .cw_min = 15, | ||
288 | .cw_max = 63, | ||
289 | .aifsn = CONF_TX_AIFS_PIFS, | ||
290 | .tx_op_limit = 1504, | ||
291 | }, | ||
292 | }, | ||
293 | .max_tx_retries = 100, | ||
294 | .ap_aging_period = 300, | ||
295 | .tid_conf_count = 4, | ||
296 | .tid_conf = { | ||
297 | [CONF_TX_AC_BE] = { | ||
298 | .queue_id = CONF_TX_AC_BE, | ||
299 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
300 | .tsid = CONF_TX_AC_BE, | ||
301 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
302 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
303 | .apsd_conf = {0, 0}, | ||
304 | }, | ||
305 | [CONF_TX_AC_BK] = { | ||
306 | .queue_id = CONF_TX_AC_BK, | ||
307 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
308 | .tsid = CONF_TX_AC_BK, | ||
309 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
310 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
311 | .apsd_conf = {0, 0}, | ||
312 | }, | ||
313 | [CONF_TX_AC_VI] = { | ||
314 | .queue_id = CONF_TX_AC_VI, | ||
315 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
316 | .tsid = CONF_TX_AC_VI, | ||
317 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
318 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
319 | .apsd_conf = {0, 0}, | ||
320 | }, | ||
321 | [CONF_TX_AC_VO] = { | ||
322 | .queue_id = CONF_TX_AC_VO, | ||
323 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | ||
324 | .tsid = CONF_TX_AC_VO, | ||
325 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | ||
326 | .ack_policy = CONF_ACK_POLICY_LEGACY, | ||
327 | .apsd_conf = {0, 0}, | ||
328 | }, | ||
329 | }, | ||
330 | .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, | ||
331 | .tx_compl_timeout = 350, | ||
332 | .tx_compl_threshold = 10, | ||
333 | .basic_rate = CONF_HW_BIT_RATE_1MBPS, | ||
334 | .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, | ||
335 | .tmpl_short_retry_limit = 10, | ||
336 | .tmpl_long_retry_limit = 10, | ||
337 | .tx_watchdog_timeout = 5000, | ||
338 | }, | ||
339 | .conn = { | ||
340 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, | ||
341 | .listen_interval = 1, | ||
342 | .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, | ||
343 | .suspend_listen_interval = 3, | ||
344 | .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, | ||
345 | .bcn_filt_ie_count = 3, | ||
346 | .bcn_filt_ie = { | ||
347 | [0] = { | ||
348 | .ie = WLAN_EID_CHANNEL_SWITCH, | ||
349 | .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, | ||
350 | }, | ||
351 | [1] = { | ||
352 | .ie = WLAN_EID_HT_OPERATION, | ||
353 | .rule = CONF_BCN_RULE_PASS_ON_CHANGE, | ||
354 | }, | ||
355 | [2] = { | ||
356 | .ie = WLAN_EID_ERP_INFO, | ||
357 | .rule = CONF_BCN_RULE_PASS_ON_CHANGE, | ||
358 | }, | ||
359 | }, | ||
360 | .synch_fail_thold = 12, | ||
361 | .bss_lose_timeout = 400, | ||
362 | .beacon_rx_timeout = 10000, | ||
363 | .broadcast_timeout = 20000, | ||
364 | .rx_broadcast_in_ps = 1, | ||
365 | .ps_poll_threshold = 10, | ||
366 | .bet_enable = CONF_BET_MODE_ENABLE, | ||
367 | .bet_max_consecutive = 50, | ||
368 | .psm_entry_retries = 8, | ||
369 | .psm_exit_retries = 16, | ||
370 | .psm_entry_nullfunc_retries = 3, | ||
371 | .dynamic_ps_timeout = 200, | ||
372 | .forced_ps = false, | ||
373 | .keep_alive_interval = 55000, | ||
374 | .max_listen_interval = 20, | ||
375 | }, | ||
376 | .itrim = { | ||
377 | .enable = false, | ||
378 | .timeout = 50000, | ||
379 | }, | ||
380 | .pm_config = { | ||
381 | .host_clk_settling_time = 5000, | ||
382 | .host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE, | ||
383 | }, | ||
384 | .roam_trigger = { | ||
385 | .trigger_pacing = 1, | ||
386 | .avg_weight_rssi_beacon = 20, | ||
387 | .avg_weight_rssi_data = 10, | ||
388 | .avg_weight_snr_beacon = 20, | ||
389 | .avg_weight_snr_data = 10, | ||
390 | }, | ||
391 | .scan = { | ||
392 | .min_dwell_time_active = 7500, | ||
393 | .max_dwell_time_active = 30000, | ||
394 | .min_dwell_time_passive = 100000, | ||
395 | .max_dwell_time_passive = 100000, | ||
396 | .num_probe_reqs = 2, | ||
397 | .split_scan_timeout = 50000, | ||
398 | }, | ||
399 | .sched_scan = { | ||
400 | /* | ||
401 | * Values are in TU/1000 but since sched scan FW command | ||
402 | * params are in TUs rounding up may occur. | ||
403 | */ | ||
404 | .base_dwell_time = 7500, | ||
405 | .max_dwell_time_delta = 22500, | ||
406 | /* based on 250bits per probe @1Mbps */ | ||
407 | .dwell_time_delta_per_probe = 2000, | ||
408 | /* based on 250bits per probe @6Mbps (plus a bit more) */ | ||
409 | .dwell_time_delta_per_probe_5 = 350, | ||
410 | .dwell_time_passive = 100000, | ||
411 | .dwell_time_dfs = 150000, | ||
412 | .num_probe_reqs = 2, | ||
413 | .rssi_threshold = -90, | ||
414 | .snr_threshold = 0, | ||
415 | }, | ||
416 | .ht = { | ||
417 | .rx_ba_win_size = 10, | ||
418 | .tx_ba_win_size = 64, | ||
419 | .inactivity_timeout = 10000, | ||
420 | .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, | ||
421 | }, | ||
422 | .mem = { | ||
423 | .num_stations = 1, | ||
424 | .ssid_profiles = 1, | ||
425 | .rx_block_num = 40, | ||
426 | .tx_min_block_num = 40, | ||
427 | .dynamic_memory = 1, | ||
428 | .min_req_tx_blocks = 45, | ||
429 | .min_req_rx_blocks = 22, | ||
430 | .tx_min = 27, | ||
431 | }, | ||
432 | .fm_coex = { | ||
433 | .enable = true, | ||
434 | .swallow_period = 5, | ||
435 | .n_divider_fref_set_1 = 0xff, /* default */ | ||
436 | .n_divider_fref_set_2 = 12, | ||
437 | .m_divider_fref_set_1 = 0xffff, | ||
438 | .m_divider_fref_set_2 = 148, /* default */ | ||
439 | .coex_pll_stabilization_time = 0xffffffff, /* default */ | ||
440 | .ldo_stabilization_time = 0xffff, /* default */ | ||
441 | .fm_disturbed_band_margin = 0xff, /* default */ | ||
442 | .swallow_clk_diff = 0xff, /* default */ | ||
443 | }, | ||
444 | .rx_streaming = { | ||
445 | .duration = 150, | ||
446 | .queues = 0x1, | ||
447 | .interval = 20, | ||
448 | .always = 0, | ||
449 | }, | ||
450 | .fwlog = { | ||
451 | .mode = WL12XX_FWLOG_ON_DEMAND, | ||
452 | .mem_blocks = 2, | ||
453 | .severity = 0, | ||
454 | .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, | ||
455 | .output = WL12XX_FWLOG_OUTPUT_HOST, | ||
456 | .threshold = 0, | ||
457 | }, | ||
458 | .rate = { | ||
459 | .rate_retry_score = 32000, | ||
460 | .per_add = 8192, | ||
461 | .per_th1 = 2048, | ||
462 | .per_th2 = 4096, | ||
463 | .max_per = 8100, | ||
464 | .inverse_curiosity_factor = 5, | ||
465 | .tx_fail_low_th = 4, | ||
466 | .tx_fail_high_th = 10, | ||
467 | .per_alpha_shift = 4, | ||
468 | .per_add_shift = 13, | ||
469 | .per_beta1_shift = 10, | ||
470 | .per_beta2_shift = 8, | ||
471 | .rate_check_up = 2, | ||
472 | .rate_check_down = 12, | ||
473 | .rate_retry_policy = { | ||
474 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
475 | 0x00, 0x00, 0x00, 0x00, 0x00, | ||
476 | 0x00, 0x00, 0x00, | ||
477 | }, | ||
478 | }, | ||
479 | .hangover = { | ||
480 | .recover_time = 0, | ||
481 | .hangover_period = 20, | ||
482 | .dynamic_mode = 1, | ||
483 | .early_termination_mode = 1, | ||
484 | .max_period = 20, | ||
485 | .min_period = 1, | ||
486 | .increase_delta = 1, | ||
487 | .decrease_delta = 2, | ||
488 | .quiet_time = 4, | ||
489 | .increase_time = 1, | ||
490 | .window_size = 16, | ||
491 | }, | ||
492 | }; | ||
493 | |||
494 | static struct wl18xx_priv_conf wl18xx_default_priv_conf = { | ||
495 | .phy = { | ||
496 | .phy_standalone = 0x00, | ||
497 | .primary_clock_setting_time = 0x05, | ||
498 | .clock_valid_on_wake_up = 0x00, | ||
499 | .secondary_clock_setting_time = 0x05, | ||
500 | .rdl = 0x01, | ||
501 | .auto_detect = 0x00, | ||
502 | .dedicated_fem = FEM_NONE, | ||
503 | .low_band_component = COMPONENT_2_WAY_SWITCH, | ||
504 | .low_band_component_type = 0x05, | ||
505 | .high_band_component = COMPONENT_2_WAY_SWITCH, | ||
506 | .high_band_component_type = 0x09, | ||
507 | .tcxo_ldo_voltage = 0x00, | ||
508 | .xtal_itrim_val = 0x04, | ||
509 | .srf_state = 0x00, | ||
510 | .io_configuration = 0x01, | ||
511 | .sdio_configuration = 0x00, | ||
512 | .settings = 0x00, | ||
513 | .enable_clpc = 0x00, | ||
514 | .enable_tx_low_pwr_on_siso_rdl = 0x00, | ||
515 | .rx_profile = 0x00, | ||
516 | .pwr_limit_reference_11_abg = 0xc8, | ||
517 | .psat = 0, | ||
518 | .low_power_val = 0x00, | ||
519 | .med_power_val = 0x0a, | ||
520 | .high_power_val = 0x1e, | ||
521 | .external_pa_dc2dc = 0, | ||
522 | .number_of_assembled_ant2_4 = 1, | ||
523 | .number_of_assembled_ant5 = 1, | ||
524 | }, | ||
525 | }; | ||
526 | |||
527 | static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = { | ||
528 | [PART_TOP_PRCM_ELP_SOC] = { | ||
529 | .mem = { .start = 0x00A02000, .size = 0x00010000 }, | ||
530 | .reg = { .start = 0x00807000, .size = 0x00005000 }, | ||
531 | .mem2 = { .start = 0x00800000, .size = 0x0000B000 }, | ||
532 | .mem3 = { .start = 0x00000000, .size = 0x00000000 }, | ||
533 | }, | ||
534 | [PART_DOWN] = { | ||
535 | .mem = { .start = 0x00000000, .size = 0x00014000 }, | ||
536 | .reg = { .start = 0x00810000, .size = 0x0000BFFF }, | ||
537 | .mem2 = { .start = 0x00000000, .size = 0x00000000 }, | ||
538 | .mem3 = { .start = 0x00000000, .size = 0x00000000 }, | ||
539 | }, | ||
540 | [PART_BOOT] = { | ||
541 | .mem = { .start = 0x00700000, .size = 0x0000030c }, | ||
542 | .reg = { .start = 0x00802000, .size = 0x00014578 }, | ||
543 | .mem2 = { .start = 0x00B00404, .size = 0x00001000 }, | ||
544 | .mem3 = { .start = 0x00C00000, .size = 0x00000400 }, | ||
545 | }, | ||
546 | [PART_WORK] = { | ||
547 | .mem = { .start = 0x00800000, .size = 0x000050FC }, | ||
548 | .reg = { .start = 0x00B00404, .size = 0x00001000 }, | ||
549 | .mem2 = { .start = 0x00C00000, .size = 0x00000400 }, | ||
550 | .mem3 = { .start = 0x00000000, .size = 0x00000000 }, | ||
551 | }, | ||
552 | [PART_PHY_INIT] = { | ||
553 | .mem = { .start = 0x80926000, | ||
554 | .size = sizeof(struct wl18xx_mac_and_phy_params) }, | ||
555 | .reg = { .start = 0x00000000, .size = 0x00000000 }, | ||
556 | .mem2 = { .start = 0x00000000, .size = 0x00000000 }, | ||
557 | .mem3 = { .start = 0x00000000, .size = 0x00000000 }, | ||
558 | }, | ||
559 | }; | ||
560 | |||
561 | static const int wl18xx_rtable[REG_TABLE_LEN] = { | ||
562 | [REG_ECPU_CONTROL] = WL18XX_REG_ECPU_CONTROL, | ||
563 | [REG_INTERRUPT_NO_CLEAR] = WL18XX_REG_INTERRUPT_NO_CLEAR, | ||
564 | [REG_INTERRUPT_ACK] = WL18XX_REG_INTERRUPT_ACK, | ||
565 | [REG_COMMAND_MAILBOX_PTR] = WL18XX_REG_COMMAND_MAILBOX_PTR, | ||
566 | [REG_EVENT_MAILBOX_PTR] = WL18XX_REG_EVENT_MAILBOX_PTR, | ||
567 | [REG_INTERRUPT_TRIG] = WL18XX_REG_INTERRUPT_TRIG_H, | ||
568 | [REG_INTERRUPT_MASK] = WL18XX_REG_INTERRUPT_MASK, | ||
569 | [REG_PC_ON_RECOVERY] = WL18XX_SCR_PAD4, | ||
570 | [REG_CHIP_ID_B] = WL18XX_REG_CHIP_ID_B, | ||
571 | [REG_CMD_MBOX_ADDRESS] = WL18XX_CMD_MBOX_ADDRESS, | ||
572 | |||
573 | /* data access memory addresses, used with partition translation */ | ||
574 | [REG_SLV_MEM_DATA] = WL18XX_SLV_MEM_DATA, | ||
575 | [REG_SLV_REG_DATA] = WL18XX_SLV_REG_DATA, | ||
576 | |||
577 | /* raw data access memory addresses */ | ||
578 | [REG_RAW_FW_STATUS_ADDR] = WL18XX_FW_STATUS_ADDR, | ||
579 | }; | ||
580 | |||
581 | static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = { | ||
582 | [CLOCK_CONFIG_16_2_M] = { 7, 104, 801, 4, true }, | ||
583 | [CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true }, | ||
584 | [CLOCK_CONFIG_16_8_M] = { 7, 100, 0, 0, false }, | ||
585 | [CLOCK_CONFIG_19_2_M] = { 8, 100, 0, 0, false }, | ||
586 | [CLOCK_CONFIG_26_M] = { 13, 120, 0, 0, false }, | ||
587 | [CLOCK_CONFIG_32_736_M] = { 9, 132, 3751, 4, true }, | ||
588 | [CLOCK_CONFIG_33_6_M] = { 7, 100, 0, 0, false }, | ||
589 | [CLOCK_CONFIG_38_468_M] = { 8, 100, 0, 0, false }, | ||
590 | [CLOCK_CONFIG_52_M] = { 13, 120, 0, 0, false }, | ||
591 | }; | ||
592 | |||
593 | /* TODO: maybe move to a new header file? */ | ||
594 | #define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin" | ||
595 | |||
596 | static int wl18xx_identify_chip(struct wl1271 *wl) | ||
597 | { | ||
598 | int ret = 0; | ||
599 | |||
600 | switch (wl->chip.id) { | ||
601 | case CHIP_ID_185x_PG20: | ||
602 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG20)", | ||
603 | wl->chip.id); | ||
604 | wl->sr_fw_name = WL18XX_FW_NAME; | ||
605 | /* wl18xx uses the same firmware for PLT */ | ||
606 | wl->plt_fw_name = WL18XX_FW_NAME; | ||
607 | wl->quirks |= WLCORE_QUIRK_NO_ELP | | ||
608 | WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | | ||
609 | WLCORE_QUIRK_TX_PAD_LAST_FRAME; | ||
610 | |||
611 | break; | ||
612 | case CHIP_ID_185x_PG10: | ||
613 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)", | ||
614 | wl->chip.id); | ||
615 | wl->sr_fw_name = WL18XX_FW_NAME; | ||
616 | /* wl18xx uses the same firmware for PLT */ | ||
617 | wl->plt_fw_name = WL18XX_FW_NAME; | ||
618 | wl->quirks |= WLCORE_QUIRK_NO_ELP | | ||
619 | WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED | | ||
620 | WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | | ||
621 | WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; | ||
622 | |||
623 | /* PG 1.0 has some problems with MCS_13, so disable it */ | ||
624 | wl->ht_cap[IEEE80211_BAND_2GHZ].mcs.rx_mask[1] &= ~BIT(5); | ||
625 | |||
626 | break; | ||
627 | default: | ||
628 | wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); | ||
629 | ret = -ENODEV; | ||
630 | goto out; | ||
631 | } | ||
632 | |||
633 | out: | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | static void wl18xx_set_clk(struct wl1271 *wl) | ||
638 | { | ||
639 | u32 clk_freq; | ||
640 | |||
641 | wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); | ||
642 | |||
643 | /* TODO: PG2: apparently we need to read the clk type */ | ||
644 | |||
645 | clk_freq = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT); | ||
646 | wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq, | ||
647 | wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m, | ||
648 | wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q, | ||
649 | wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit"); | ||
650 | |||
651 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, wl18xx_clk_table[clk_freq].n); | ||
652 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M, wl18xx_clk_table[clk_freq].m); | ||
653 | |||
654 | if (wl18xx_clk_table[clk_freq].swallow) { | ||
655 | /* first the 16 lower bits */ | ||
656 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1, | ||
657 | wl18xx_clk_table[clk_freq].q & | ||
658 | PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK); | ||
659 | /* then the 16 higher bits, masked out */ | ||
660 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2, | ||
661 | (wl18xx_clk_table[clk_freq].q >> 16) & | ||
662 | PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK); | ||
663 | |||
664 | /* first the 16 lower bits */ | ||
665 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1, | ||
666 | wl18xx_clk_table[clk_freq].p & | ||
667 | PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK); | ||
668 | /* then the 16 higher bits, masked out */ | ||
669 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2, | ||
670 | (wl18xx_clk_table[clk_freq].p >> 16) & | ||
671 | PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK); | ||
672 | } else { | ||
673 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN, | ||
674 | PLLSH_WCS_PLL_SWALLOW_EN_VAL2); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | static void wl18xx_boot_soft_reset(struct wl1271 *wl) | ||
679 | { | ||
680 | /* disable Rx/Tx */ | ||
681 | wl1271_write32(wl, WL18XX_ENABLE, 0x0); | ||
682 | |||
683 | /* disable auto calibration on start*/ | ||
684 | wl1271_write32(wl, WL18XX_SPARE_A2, 0xffff); | ||
685 | } | ||
686 | |||
687 | static int wl18xx_pre_boot(struct wl1271 *wl) | ||
688 | { | ||
689 | wl18xx_set_clk(wl); | ||
690 | |||
691 | /* Continue the ELP wake up sequence */ | ||
692 | wl1271_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); | ||
693 | udelay(500); | ||
694 | |||
695 | wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); | ||
696 | |||
697 | /* Disable interrupts */ | ||
698 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | ||
699 | |||
700 | wl18xx_boot_soft_reset(wl); | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | static void wl18xx_pre_upload(struct wl1271 *wl) | ||
706 | { | ||
707 | u32 tmp; | ||
708 | |||
709 | wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); | ||
710 | |||
711 | /* TODO: check if this is all needed */ | ||
712 | wl1271_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND); | ||
713 | |||
714 | tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); | ||
715 | |||
716 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); | ||
717 | |||
718 | tmp = wl1271_read32(wl, WL18XX_SCR_PAD2); | ||
719 | } | ||
720 | |||
721 | static void wl18xx_set_mac_and_phy(struct wl1271 *wl) | ||
722 | { | ||
723 | struct wl18xx_priv *priv = wl->priv; | ||
724 | size_t len; | ||
725 | |||
726 | /* the parameters struct is smaller for PG1 */ | ||
727 | if (wl->chip.id == CHIP_ID_185x_PG10) | ||
728 | len = offsetof(struct wl18xx_mac_and_phy_params, psat) + 1; | ||
729 | else | ||
730 | len = sizeof(struct wl18xx_mac_and_phy_params); | ||
731 | |||
732 | wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]); | ||
733 | wl1271_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy, len, | ||
734 | false); | ||
735 | } | ||
736 | |||
737 | static void wl18xx_enable_interrupts(struct wl1271 *wl) | ||
738 | { | ||
739 | u32 event_mask, intr_mask; | ||
740 | |||
741 | if (wl->chip.id == CHIP_ID_185x_PG10) { | ||
742 | event_mask = WL18XX_ACX_EVENTS_VECTOR_PG1; | ||
743 | intr_mask = WL18XX_INTR_MASK_PG1; | ||
744 | } else { | ||
745 | event_mask = WL18XX_ACX_EVENTS_VECTOR_PG2; | ||
746 | intr_mask = WL18XX_INTR_MASK_PG2; | ||
747 | } | ||
748 | |||
749 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask); | ||
750 | |||
751 | wlcore_enable_interrupts(wl); | ||
752 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, | ||
753 | WL1271_ACX_INTR_ALL & ~intr_mask); | ||
754 | } | ||
755 | |||
756 | static int wl18xx_boot(struct wl1271 *wl) | ||
757 | { | ||
758 | int ret; | ||
759 | |||
760 | ret = wl18xx_pre_boot(wl); | ||
761 | if (ret < 0) | ||
762 | goto out; | ||
763 | |||
764 | wl18xx_pre_upload(wl); | ||
765 | |||
766 | ret = wlcore_boot_upload_firmware(wl); | ||
767 | if (ret < 0) | ||
768 | goto out; | ||
769 | |||
770 | wl18xx_set_mac_and_phy(wl); | ||
771 | |||
772 | ret = wlcore_boot_run_firmware(wl); | ||
773 | if (ret < 0) | ||
774 | goto out; | ||
775 | |||
776 | wl18xx_enable_interrupts(wl); | ||
777 | |||
778 | out: | ||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | static void wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, | ||
783 | void *buf, size_t len) | ||
784 | { | ||
785 | struct wl18xx_priv *priv = wl->priv; | ||
786 | |||
787 | memcpy(priv->cmd_buf, buf, len); | ||
788 | memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len); | ||
789 | |||
790 | wl1271_write(wl, cmd_box_addr, priv->cmd_buf, WL18XX_CMD_MAX_SIZE, | ||
791 | false); | ||
792 | } | ||
793 | |||
794 | static void wl18xx_ack_event(struct wl1271 *wl) | ||
795 | { | ||
796 | wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL18XX_INTR_TRIG_EVENT_ACK); | ||
797 | } | ||
798 | |||
799 | static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) | ||
800 | { | ||
801 | u32 blk_size = WL18XX_TX_HW_BLOCK_SIZE; | ||
802 | return (len + blk_size - 1) / blk_size + spare_blks; | ||
803 | } | ||
804 | |||
805 | static void | ||
806 | wl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, | ||
807 | u32 blks, u32 spare_blks) | ||
808 | { | ||
809 | desc->wl18xx_mem.total_mem_blocks = blks; | ||
810 | } | ||
811 | |||
812 | static void | ||
813 | wl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, | ||
814 | struct sk_buff *skb) | ||
815 | { | ||
816 | desc->length = cpu_to_le16(skb->len); | ||
817 | |||
818 | /* if only the last frame is to be padded, we unset this bit on Tx */ | ||
819 | if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) | ||
820 | desc->wl18xx_mem.ctrl = WL18XX_TX_CTRL_NOT_PADDED; | ||
821 | else | ||
822 | desc->wl18xx_mem.ctrl = 0; | ||
823 | |||
824 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " | ||
825 | "len: %d life: %d mem: %d", desc->hlid, | ||
826 | le16_to_cpu(desc->length), | ||
827 | le16_to_cpu(desc->life_time), | ||
828 | desc->wl18xx_mem.total_mem_blocks); | ||
829 | } | ||
830 | |||
831 | static enum wl_rx_buf_align | ||
832 | wl18xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) | ||
833 | { | ||
834 | if (rx_desc & RX_BUF_PADDED_PAYLOAD) | ||
835 | return WLCORE_RX_BUF_PADDED; | ||
836 | |||
837 | return WLCORE_RX_BUF_ALIGNED; | ||
838 | } | ||
839 | |||
840 | static u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data, | ||
841 | u32 data_len) | ||
842 | { | ||
843 | struct wl1271_rx_descriptor *desc = rx_data; | ||
844 | |||
845 | /* invalid packet */ | ||
846 | if (data_len < sizeof(*desc)) | ||
847 | return 0; | ||
848 | |||
849 | return data_len - sizeof(*desc); | ||
850 | } | ||
851 | |||
852 | static void wl18xx_tx_immediate_completion(struct wl1271 *wl) | ||
853 | { | ||
854 | wl18xx_tx_immediate_complete(wl); | ||
855 | } | ||
856 | |||
857 | static int wl18xx_set_host_cfg_bitmap(struct wl1271 *wl, u32 extra_mem_blk) | ||
858 | { | ||
859 | int ret; | ||
860 | u32 sdio_align_size = 0; | ||
861 | u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE | | ||
862 | HOST_IF_CFG_ADD_RX_ALIGNMENT; | ||
863 | |||
864 | /* Enable Tx SDIO padding */ | ||
865 | if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) { | ||
866 | host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; | ||
867 | sdio_align_size = WL12XX_BUS_BLOCK_SIZE; | ||
868 | } | ||
869 | |||
870 | /* Enable Rx SDIO padding */ | ||
871 | if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) { | ||
872 | host_cfg_bitmap |= HOST_IF_CFG_RX_PAD_TO_SDIO_BLK; | ||
873 | sdio_align_size = WL12XX_BUS_BLOCK_SIZE; | ||
874 | } | ||
875 | |||
876 | ret = wl18xx_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap, | ||
877 | sdio_align_size, extra_mem_blk, | ||
878 | WL18XX_HOST_IF_LEN_SIZE_FIELD); | ||
879 | if (ret < 0) | ||
880 | return ret; | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static int wl18xx_hw_init(struct wl1271 *wl) | ||
886 | { | ||
887 | int ret; | ||
888 | struct wl18xx_priv *priv = wl->priv; | ||
889 | |||
890 | /* (re)init private structures. Relevant on recovery as well. */ | ||
891 | priv->last_fw_rls_idx = 0; | ||
892 | priv->extra_spare_vif_count = 0; | ||
893 | |||
894 | /* set the default amount of spare blocks in the bitmap */ | ||
895 | ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE); | ||
896 | if (ret < 0) | ||
897 | return ret; | ||
898 | |||
899 | if (checksum_param) { | ||
900 | ret = wl18xx_acx_set_checksum_state(wl); | ||
901 | if (ret != 0) | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | return ret; | ||
906 | } | ||
907 | |||
908 | static void wl18xx_set_tx_desc_csum(struct wl1271 *wl, | ||
909 | struct wl1271_tx_hw_descr *desc, | ||
910 | struct sk_buff *skb) | ||
911 | { | ||
912 | u32 ip_hdr_offset; | ||
913 | struct iphdr *ip_hdr; | ||
914 | |||
915 | if (!checksum_param) { | ||
916 | desc->wl18xx_checksum_data = 0; | ||
917 | return; | ||
918 | } | ||
919 | |||
920 | if (skb->ip_summed != CHECKSUM_PARTIAL) { | ||
921 | desc->wl18xx_checksum_data = 0; | ||
922 | return; | ||
923 | } | ||
924 | |||
925 | ip_hdr_offset = skb_network_header(skb) - skb_mac_header(skb); | ||
926 | if (WARN_ON(ip_hdr_offset >= (1<<7))) { | ||
927 | desc->wl18xx_checksum_data = 0; | ||
928 | return; | ||
929 | } | ||
930 | |||
931 | desc->wl18xx_checksum_data = ip_hdr_offset << 1; | ||
932 | |||
933 | /* FW is interested only in the LSB of the protocol TCP=0 UDP=1 */ | ||
934 | ip_hdr = (void *)skb_network_header(skb); | ||
935 | desc->wl18xx_checksum_data |= (ip_hdr->protocol & 0x01); | ||
936 | } | ||
937 | |||
938 | static void wl18xx_set_rx_csum(struct wl1271 *wl, | ||
939 | struct wl1271_rx_descriptor *desc, | ||
940 | struct sk_buff *skb) | ||
941 | { | ||
942 | if (desc->status & WL18XX_RX_CHECKSUM_MASK) | ||
943 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
944 | } | ||
945 | |||
946 | /* | ||
947 | * TODO: instead of having these two functions to get the rate mask, | ||
948 | * we should modify the wlvif->rate_set instead | ||
949 | */ | ||
950 | static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl, | ||
951 | struct wl12xx_vif *wlvif) | ||
952 | { | ||
953 | u32 hw_rate_set = wlvif->rate_set; | ||
954 | |||
955 | if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || | ||
956 | wlvif->channel_type == NL80211_CHAN_HT40PLUS) { | ||
957 | wl1271_debug(DEBUG_ACX, "using wide channel rate mask"); | ||
958 | hw_rate_set |= CONF_TX_RATE_USE_WIDE_CHAN; | ||
959 | |||
960 | /* we don't support MIMO in wide-channel mode */ | ||
961 | hw_rate_set &= ~CONF_TX_MIMO_RATES; | ||
962 | } | ||
963 | |||
964 | return hw_rate_set; | ||
965 | } | ||
966 | |||
967 | static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, | ||
968 | struct wl12xx_vif *wlvif) | ||
969 | { | ||
970 | if ((wlvif->channel_type == NL80211_CHAN_HT40MINUS || | ||
971 | wlvif->channel_type == NL80211_CHAN_HT40PLUS) && | ||
972 | !strcmp(ht_mode_param, "wide")) { | ||
973 | wl1271_debug(DEBUG_ACX, "using wide channel rate mask"); | ||
974 | return CONF_TX_RATE_USE_WIDE_CHAN; | ||
975 | } else if (!strcmp(ht_mode_param, "mimo")) { | ||
976 | wl1271_debug(DEBUG_ACX, "using MIMO rate mask"); | ||
977 | |||
978 | /* | ||
979 | * PG 1.0 has some problems with MCS_13, so disable it | ||
980 | * | ||
981 | * TODO: instead of hacking this in here, we should | ||
982 | * make it more general and change a bit in the | ||
983 | * wlvif->rate_set instead. | ||
984 | */ | ||
985 | if (wl->chip.id == CHIP_ID_185x_PG10) | ||
986 | return CONF_TX_MIMO_RATES & ~CONF_HW_BIT_RATE_MCS_13; | ||
987 | |||
988 | return CONF_TX_MIMO_RATES; | ||
989 | } else { | ||
990 | return 0; | ||
991 | } | ||
992 | } | ||
993 | |||
994 | static s8 wl18xx_get_pg_ver(struct wl1271 *wl) | ||
995 | { | ||
996 | u32 fuse; | ||
997 | |||
998 | wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); | ||
999 | |||
1000 | fuse = wl1271_read32(wl, WL18XX_REG_FUSE_DATA_1_3); | ||
1001 | fuse = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; | ||
1002 | |||
1003 | wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); | ||
1004 | |||
1005 | return (s8)fuse; | ||
1006 | } | ||
1007 | |||
1008 | #define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin" | ||
1009 | static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev) | ||
1010 | { | ||
1011 | struct wl18xx_priv *priv = wl->priv; | ||
1012 | struct wlcore_conf_file *conf_file; | ||
1013 | const struct firmware *fw; | ||
1014 | int ret; | ||
1015 | |||
1016 | ret = request_firmware(&fw, WL18XX_CONF_FILE_NAME, dev); | ||
1017 | if (ret < 0) { | ||
1018 | wl1271_error("could not get configuration binary %s: %d", | ||
1019 | WL18XX_CONF_FILE_NAME, ret); | ||
1020 | goto out_fallback; | ||
1021 | } | ||
1022 | |||
1023 | if (fw->size != WL18XX_CONF_SIZE) { | ||
1024 | wl1271_error("configuration binary file size is wrong, " | ||
1025 | "expected %ld got %zd", | ||
1026 | WL18XX_CONF_SIZE, fw->size); | ||
1027 | ret = -EINVAL; | ||
1028 | goto out; | ||
1029 | } | ||
1030 | |||
1031 | conf_file = (struct wlcore_conf_file *) fw->data; | ||
1032 | |||
1033 | if (conf_file->header.magic != cpu_to_le32(WL18XX_CONF_MAGIC)) { | ||
1034 | wl1271_error("configuration binary file magic number mismatch, " | ||
1035 | "expected 0x%0x got 0x%0x", WL18XX_CONF_MAGIC, | ||
1036 | conf_file->header.magic); | ||
1037 | ret = -EINVAL; | ||
1038 | goto out; | ||
1039 | } | ||
1040 | |||
1041 | if (conf_file->header.version != cpu_to_le32(WL18XX_CONF_VERSION)) { | ||
1042 | wl1271_error("configuration binary file version not supported, " | ||
1043 | "expected 0x%08x got 0x%08x", | ||
1044 | WL18XX_CONF_VERSION, conf_file->header.version); | ||
1045 | ret = -EINVAL; | ||
1046 | goto out; | ||
1047 | } | ||
1048 | |||
1049 | memcpy(&wl->conf, &conf_file->core, sizeof(wl18xx_conf)); | ||
1050 | memcpy(&priv->conf, &conf_file->priv, sizeof(priv->conf)); | ||
1051 | |||
1052 | goto out; | ||
1053 | |||
1054 | out_fallback: | ||
1055 | wl1271_warning("falling back to default config"); | ||
1056 | |||
1057 | /* apply driver default configuration */ | ||
1058 | memcpy(&wl->conf, &wl18xx_conf, sizeof(wl18xx_conf)); | ||
1059 | /* apply default private configuration */ | ||
1060 | memcpy(&priv->conf, &wl18xx_default_priv_conf, sizeof(priv->conf)); | ||
1061 | |||
1062 | /* For now we just fallback */ | ||
1063 | return 0; | ||
1064 | |||
1065 | out: | ||
1066 | release_firmware(fw); | ||
1067 | return ret; | ||
1068 | } | ||
1069 | |||
1070 | static int wl18xx_plt_init(struct wl1271 *wl) | ||
1071 | { | ||
1072 | wl1271_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT); | ||
1073 | |||
1074 | return wl->ops->boot(wl); | ||
1075 | } | ||
1076 | |||
1077 | static void wl18xx_get_mac(struct wl1271 *wl) | ||
1078 | { | ||
1079 | u32 mac1, mac2; | ||
1080 | |||
1081 | wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); | ||
1082 | |||
1083 | mac1 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1); | ||
1084 | mac2 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2); | ||
1085 | |||
1086 | /* these are the two parts of the BD_ADDR */ | ||
1087 | wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + | ||
1088 | ((mac1 & 0xff000000) >> 24); | ||
1089 | wl->fuse_nic_addr = (mac1 & 0xffffff); | ||
1090 | |||
1091 | wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); | ||
1092 | } | ||
1093 | |||
1094 | static int wl18xx_handle_static_data(struct wl1271 *wl, | ||
1095 | struct wl1271_static_data *static_data) | ||
1096 | { | ||
1097 | struct wl18xx_static_data_priv *static_data_priv = | ||
1098 | (struct wl18xx_static_data_priv *) static_data->priv; | ||
1099 | |||
1100 | wl1271_info("PHY firmware version: %s", static_data_priv->phy_version); | ||
1101 | |||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | static int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem) | ||
1106 | { | ||
1107 | struct wl18xx_priv *priv = wl->priv; | ||
1108 | |||
1109 | /* If we have VIFs requiring extra spare, indulge them */ | ||
1110 | if (priv->extra_spare_vif_count) | ||
1111 | return WL18XX_TX_HW_EXTRA_BLOCK_SPARE; | ||
1112 | |||
1113 | return WL18XX_TX_HW_BLOCK_SPARE; | ||
1114 | } | ||
1115 | |||
1116 | static int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, | ||
1117 | struct ieee80211_vif *vif, | ||
1118 | struct ieee80211_sta *sta, | ||
1119 | struct ieee80211_key_conf *key_conf) | ||
1120 | { | ||
1121 | struct wl18xx_priv *priv = wl->priv; | ||
1122 | bool change_spare = false; | ||
1123 | int ret; | ||
1124 | |||
1125 | /* | ||
1126 | * when adding the first or removing the last GEM/TKIP interface, | ||
1127 | * we have to adjust the number of spare blocks. | ||
1128 | */ | ||
1129 | change_spare = (key_conf->cipher == WL1271_CIPHER_SUITE_GEM || | ||
1130 | key_conf->cipher == WLAN_CIPHER_SUITE_TKIP) && | ||
1131 | ((priv->extra_spare_vif_count == 0 && cmd == SET_KEY) || | ||
1132 | (priv->extra_spare_vif_count == 1 && cmd == DISABLE_KEY)); | ||
1133 | |||
1134 | /* no need to change spare - just regular set_key */ | ||
1135 | if (!change_spare) | ||
1136 | return wlcore_set_key(wl, cmd, vif, sta, key_conf); | ||
1137 | |||
1138 | /* | ||
1139 | * stop the queues and flush to ensure the next packets are | ||
1140 | * in sync with FW spare block accounting | ||
1141 | */ | ||
1142 | wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); | ||
1143 | wl1271_tx_flush(wl); | ||
1144 | |||
1145 | ret = wlcore_set_key(wl, cmd, vif, sta, key_conf); | ||
1146 | if (ret < 0) | ||
1147 | goto out; | ||
1148 | |||
1149 | /* key is now set, change the spare blocks */ | ||
1150 | if (cmd == SET_KEY) { | ||
1151 | ret = wl18xx_set_host_cfg_bitmap(wl, | ||
1152 | WL18XX_TX_HW_EXTRA_BLOCK_SPARE); | ||
1153 | if (ret < 0) | ||
1154 | goto out; | ||
1155 | |||
1156 | priv->extra_spare_vif_count++; | ||
1157 | } else { | ||
1158 | ret = wl18xx_set_host_cfg_bitmap(wl, | ||
1159 | WL18XX_TX_HW_BLOCK_SPARE); | ||
1160 | if (ret < 0) | ||
1161 | goto out; | ||
1162 | |||
1163 | priv->extra_spare_vif_count--; | ||
1164 | } | ||
1165 | |||
1166 | out: | ||
1167 | wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_SPARE_BLK); | ||
1168 | return ret; | ||
1169 | } | ||
1170 | |||
1171 | static u32 wl18xx_pre_pkt_send(struct wl1271 *wl, | ||
1172 | u32 buf_offset, u32 last_len) | ||
1173 | { | ||
1174 | if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) { | ||
1175 | struct wl1271_tx_hw_descr *last_desc; | ||
1176 | |||
1177 | /* get the last TX HW descriptor written to the aggr buf */ | ||
1178 | last_desc = (struct wl1271_tx_hw_descr *)(wl->aggr_buf + | ||
1179 | buf_offset - last_len); | ||
1180 | |||
1181 | /* the last frame is padded up to an SDIO block */ | ||
1182 | last_desc->wl18xx_mem.ctrl &= ~WL18XX_TX_CTRL_NOT_PADDED; | ||
1183 | return ALIGN(buf_offset, WL12XX_BUS_BLOCK_SIZE); | ||
1184 | } | ||
1185 | |||
1186 | /* no modifications */ | ||
1187 | return buf_offset; | ||
1188 | } | ||
1189 | |||
1190 | static struct wlcore_ops wl18xx_ops = { | ||
1191 | .identify_chip = wl18xx_identify_chip, | ||
1192 | .boot = wl18xx_boot, | ||
1193 | .plt_init = wl18xx_plt_init, | ||
1194 | .trigger_cmd = wl18xx_trigger_cmd, | ||
1195 | .ack_event = wl18xx_ack_event, | ||
1196 | .calc_tx_blocks = wl18xx_calc_tx_blocks, | ||
1197 | .set_tx_desc_blocks = wl18xx_set_tx_desc_blocks, | ||
1198 | .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len, | ||
1199 | .get_rx_buf_align = wl18xx_get_rx_buf_align, | ||
1200 | .get_rx_packet_len = wl18xx_get_rx_packet_len, | ||
1201 | .tx_immediate_compl = wl18xx_tx_immediate_completion, | ||
1202 | .tx_delayed_compl = NULL, | ||
1203 | .hw_init = wl18xx_hw_init, | ||
1204 | .set_tx_desc_csum = wl18xx_set_tx_desc_csum, | ||
1205 | .get_pg_ver = wl18xx_get_pg_ver, | ||
1206 | .set_rx_csum = wl18xx_set_rx_csum, | ||
1207 | .sta_get_ap_rate_mask = wl18xx_sta_get_ap_rate_mask, | ||
1208 | .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask, | ||
1209 | .get_mac = wl18xx_get_mac, | ||
1210 | .debugfs_init = wl18xx_debugfs_add_files, | ||
1211 | .handle_static_data = wl18xx_handle_static_data, | ||
1212 | .get_spare_blocks = wl18xx_get_spare_blocks, | ||
1213 | .set_key = wl18xx_set_key, | ||
1214 | .pre_pkt_send = wl18xx_pre_pkt_send, | ||
1215 | }; | ||
1216 | |||
1217 | /* HT cap appropriate for wide channels */ | ||
1218 | static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap = { | ||
1219 | .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | | ||
1220 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40, | ||
1221 | .ht_supported = true, | ||
1222 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | ||
1223 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | ||
1224 | .mcs = { | ||
1225 | .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, | ||
1226 | .rx_highest = cpu_to_le16(150), | ||
1227 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
1228 | }, | ||
1229 | }; | ||
1230 | |||
1231 | /* HT cap appropriate for SISO 20 */ | ||
1232 | static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = { | ||
1233 | .cap = IEEE80211_HT_CAP_SGI_20, | ||
1234 | .ht_supported = true, | ||
1235 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | ||
1236 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | ||
1237 | .mcs = { | ||
1238 | .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, | ||
1239 | .rx_highest = cpu_to_le16(72), | ||
1240 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
1241 | }, | ||
1242 | }; | ||
1243 | |||
1244 | /* HT cap appropriate for MIMO rates in 20mhz channel */ | ||
1245 | static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { | ||
1246 | .cap = IEEE80211_HT_CAP_SGI_20, | ||
1247 | .ht_supported = true, | ||
1248 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | ||
1249 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | ||
1250 | .mcs = { | ||
1251 | .rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, }, | ||
1252 | .rx_highest = cpu_to_le16(144), | ||
1253 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
1254 | }, | ||
1255 | }; | ||
1256 | |||
1257 | static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_5ghz = { | ||
1258 | .cap = IEEE80211_HT_CAP_SGI_20, | ||
1259 | .ht_supported = true, | ||
1260 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | ||
1261 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | ||
1262 | .mcs = { | ||
1263 | .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, | ||
1264 | .rx_highest = cpu_to_le16(72), | ||
1265 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
1266 | }, | ||
1267 | }; | ||
1268 | |||
1269 | static int __devinit wl18xx_probe(struct platform_device *pdev) | ||
1270 | { | ||
1271 | struct wl1271 *wl; | ||
1272 | struct ieee80211_hw *hw; | ||
1273 | struct wl18xx_priv *priv; | ||
1274 | int ret; | ||
1275 | |||
1276 | hw = wlcore_alloc_hw(sizeof(*priv)); | ||
1277 | if (IS_ERR(hw)) { | ||
1278 | wl1271_error("can't allocate hw"); | ||
1279 | ret = PTR_ERR(hw); | ||
1280 | goto out; | ||
1281 | } | ||
1282 | |||
1283 | wl = hw->priv; | ||
1284 | priv = wl->priv; | ||
1285 | wl->ops = &wl18xx_ops; | ||
1286 | wl->ptable = wl18xx_ptable; | ||
1287 | wl->rtable = wl18xx_rtable; | ||
1288 | wl->num_tx_desc = 32; | ||
1289 | wl->num_rx_desc = 16; | ||
1290 | wl->band_rate_to_idx = wl18xx_band_rate_to_idx; | ||
1291 | wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX; | ||
1292 | wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0; | ||
1293 | wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv); | ||
1294 | wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics); | ||
1295 | wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv); | ||
1296 | |||
1297 | if (!strcmp(ht_mode_param, "wide")) { | ||
1298 | memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], | ||
1299 | &wl18xx_siso40_ht_cap, | ||
1300 | sizeof(wl18xx_siso40_ht_cap)); | ||
1301 | memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], | ||
1302 | &wl18xx_siso40_ht_cap, | ||
1303 | sizeof(wl18xx_siso40_ht_cap)); | ||
1304 | } else if (!strcmp(ht_mode_param, "mimo")) { | ||
1305 | memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], | ||
1306 | &wl18xx_mimo_ht_cap_2ghz, | ||
1307 | sizeof(wl18xx_mimo_ht_cap_2ghz)); | ||
1308 | memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], | ||
1309 | &wl18xx_mimo_ht_cap_5ghz, | ||
1310 | sizeof(wl18xx_mimo_ht_cap_5ghz)); | ||
1311 | } else if (!strcmp(ht_mode_param, "siso20")) { | ||
1312 | memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], | ||
1313 | &wl18xx_siso20_ht_cap, | ||
1314 | sizeof(wl18xx_siso20_ht_cap)); | ||
1315 | memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], | ||
1316 | &wl18xx_siso20_ht_cap, | ||
1317 | sizeof(wl18xx_siso20_ht_cap)); | ||
1318 | } else { | ||
1319 | wl1271_error("invalid ht_mode '%s'", ht_mode_param); | ||
1320 | ret = -EINVAL; | ||
1321 | goto out_free; | ||
1322 | } | ||
1323 | |||
1324 | ret = wl18xx_conf_init(wl, &pdev->dev); | ||
1325 | if (ret < 0) | ||
1326 | goto out_free; | ||
1327 | |||
1328 | if (!strcmp(board_type_param, "fpga")) { | ||
1329 | priv->conf.phy.board_type = BOARD_TYPE_FPGA_18XX; | ||
1330 | } else if (!strcmp(board_type_param, "hdk")) { | ||
1331 | priv->conf.phy.board_type = BOARD_TYPE_HDK_18XX; | ||
1332 | /* HACK! Just for now we hardcode HDK to 0x06 */ | ||
1333 | priv->conf.phy.low_band_component_type = 0x06; | ||
1334 | } else if (!strcmp(board_type_param, "dvp")) { | ||
1335 | priv->conf.phy.board_type = BOARD_TYPE_DVP_18XX; | ||
1336 | } else if (!strcmp(board_type_param, "evb")) { | ||
1337 | priv->conf.phy.board_type = BOARD_TYPE_EVB_18XX; | ||
1338 | } else if (!strcmp(board_type_param, "com8")) { | ||
1339 | priv->conf.phy.board_type = BOARD_TYPE_COM8_18XX; | ||
1340 | /* HACK! Just for now we hardcode COM8 to 0x06 */ | ||
1341 | priv->conf.phy.low_band_component_type = 0x06; | ||
1342 | } else { | ||
1343 | wl1271_error("invalid board type '%s'", board_type_param); | ||
1344 | ret = -EINVAL; | ||
1345 | goto out_free; | ||
1346 | } | ||
1347 | |||
1348 | /* If the module param is set, update it in conf */ | ||
1349 | if (low_band_component_param != -1) | ||
1350 | priv->conf.phy.low_band_component = low_band_component_param; | ||
1351 | if (low_band_component_type_param != -1) | ||
1352 | priv->conf.phy.low_band_component_type = | ||
1353 | low_band_component_type_param; | ||
1354 | if (high_band_component_param != -1) | ||
1355 | priv->conf.phy.high_band_component = high_band_component_param; | ||
1356 | if (high_band_component_type_param != -1) | ||
1357 | priv->conf.phy.high_band_component_type = | ||
1358 | high_band_component_type_param; | ||
1359 | if (pwr_limit_reference_11_abg_param != -1) | ||
1360 | priv->conf.phy.pwr_limit_reference_11_abg = | ||
1361 | pwr_limit_reference_11_abg_param; | ||
1362 | if (n_antennas_2_param != -1) | ||
1363 | priv->conf.phy.number_of_assembled_ant2_4 = n_antennas_2_param; | ||
1364 | if (n_antennas_5_param != -1) | ||
1365 | priv->conf.phy.number_of_assembled_ant5 = n_antennas_5_param; | ||
1366 | if (dc2dc_param != -1) | ||
1367 | priv->conf.phy.external_pa_dc2dc = dc2dc_param; | ||
1368 | |||
1369 | if (!checksum_param) { | ||
1370 | wl18xx_ops.set_rx_csum = NULL; | ||
1371 | wl18xx_ops.init_vif = NULL; | ||
1372 | } | ||
1373 | |||
1374 | wl->enable_11a = enable_11a_param; | ||
1375 | |||
1376 | return wlcore_probe(wl, pdev); | ||
1377 | |||
1378 | out_free: | ||
1379 | wlcore_free_hw(wl); | ||
1380 | out: | ||
1381 | return ret; | ||
1382 | } | ||
1383 | |||
1384 | static const struct platform_device_id wl18xx_id_table[] __devinitconst = { | ||
1385 | { "wl18xx", 0 }, | ||
1386 | { } /* Terminating Entry */ | ||
1387 | }; | ||
1388 | MODULE_DEVICE_TABLE(platform, wl18xx_id_table); | ||
1389 | |||
1390 | static struct platform_driver wl18xx_driver = { | ||
1391 | .probe = wl18xx_probe, | ||
1392 | .remove = __devexit_p(wlcore_remove), | ||
1393 | .id_table = wl18xx_id_table, | ||
1394 | .driver = { | ||
1395 | .name = "wl18xx_driver", | ||
1396 | .owner = THIS_MODULE, | ||
1397 | } | ||
1398 | }; | ||
1399 | |||
1400 | static int __init wl18xx_init(void) | ||
1401 | { | ||
1402 | return platform_driver_register(&wl18xx_driver); | ||
1403 | } | ||
1404 | module_init(wl18xx_init); | ||
1405 | |||
1406 | static void __exit wl18xx_exit(void) | ||
1407 | { | ||
1408 | platform_driver_unregister(&wl18xx_driver); | ||
1409 | } | ||
1410 | module_exit(wl18xx_exit); | ||
1411 | |||
1412 | module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR); | ||
1413 | MODULE_PARM_DESC(ht_mode, "Force HT mode: wide (default), mimo or siso20"); | ||
1414 | |||
1415 | module_param_named(board_type, board_type_param, charp, S_IRUSR); | ||
1416 | MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or " | ||
1417 | "dvp"); | ||
1418 | |||
1419 | module_param_named(checksum, checksum_param, bool, S_IRUSR); | ||
1420 | MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)"); | ||
1421 | |||
1422 | module_param_named(enable_11a, enable_11a_param, bool, S_IRUSR); | ||
1423 | MODULE_PARM_DESC(enable_11a, "Enable 11a (5GHz): boolean (defaults to true)"); | ||
1424 | |||
1425 | module_param_named(dc2dc, dc2dc_param, int, S_IRUSR); | ||
1426 | MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)"); | ||
1427 | |||
1428 | module_param_named(n_antennas_2, n_antennas_2_param, int, S_IRUSR); | ||
1429 | MODULE_PARM_DESC(n_antennas_2, | ||
1430 | "Number of installed 2.4GHz antennas: 1 (default) or 2"); | ||
1431 | |||
1432 | module_param_named(n_antennas_5, n_antennas_5_param, int, S_IRUSR); | ||
1433 | MODULE_PARM_DESC(n_antennas_5, | ||
1434 | "Number of installed 5GHz antennas: 1 (default) or 2"); | ||
1435 | |||
1436 | module_param_named(low_band_component, low_band_component_param, int, | ||
1437 | S_IRUSR); | ||
1438 | MODULE_PARM_DESC(low_band_component, "Low band component: u8 " | ||
1439 | "(default is 0x01)"); | ||
1440 | |||
1441 | module_param_named(low_band_component_type, low_band_component_type_param, | ||
1442 | int, S_IRUSR); | ||
1443 | MODULE_PARM_DESC(low_band_component_type, "Low band component type: u8 " | ||
1444 | "(default is 0x05 or 0x06 depending on the board_type)"); | ||
1445 | |||
1446 | module_param_named(high_band_component, high_band_component_param, int, | ||
1447 | S_IRUSR); | ||
1448 | MODULE_PARM_DESC(high_band_component, "High band component: u8, " | ||
1449 | "(default is 0x01)"); | ||
1450 | |||
1451 | module_param_named(high_band_component_type, high_band_component_type_param, | ||
1452 | int, S_IRUSR); | ||
1453 | MODULE_PARM_DESC(high_band_component_type, "High band component type: u8 " | ||
1454 | "(default is 0x09)"); | ||
1455 | |||
1456 | module_param_named(pwr_limit_reference_11_abg, | ||
1457 | pwr_limit_reference_11_abg_param, int, S_IRUSR); | ||
1458 | MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 " | ||
1459 | "(default is 0xc8)"); | ||
1460 | |||
1461 | MODULE_LICENSE("GPL v2"); | ||
1462 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); | ||
1463 | MODULE_FIRMWARE(WL18XX_FW_NAME); | ||