Commit | Line | Data |
---|---|---|
9a1a6990 LC |
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> | |
2fc28de5 | 24 | #include <linux/ip.h> |
9a1a6990 LC |
25 | |
26 | #include "../wlcore/wlcore.h" | |
27 | #include "../wlcore/debug.h" | |
46a1d512 LC |
28 | #include "../wlcore/io.h" |
29 | #include "../wlcore/acx.h" | |
fb0f2e4a | 30 | #include "../wlcore/tx.h" |
9c809f88 AN |
31 | #include "../wlcore/rx.h" |
32 | #include "../wlcore/io.h" | |
46a1d512 | 33 | #include "../wlcore/boot.h" |
9a1a6990 | 34 | |
5d4a9fa6 | 35 | #include "reg.h" |
46a1d512 | 36 | #include "conf.h" |
b8422dcb | 37 | #include "acx.h" |
872b345f | 38 | #include "tx.h" |
274c66cd | 39 | #include "wl18xx.h" |
be65202a | 40 | #include "io.h" |
46a1d512 | 41 | |
1349c421 | 42 | |
169da04f AN |
43 | #define WL18XX_RX_CHECKSUM_MASK 0x40 |
44 | ||
3a8ddb61 | 45 | static char *ht_mode_param; |
a9c130d5 | 46 | static char *board_type_param; |
3a8ddb61 | 47 | |
f648eab7 AN |
48 | static const u8 wl18xx_rate_to_idx_2ghz[] = { |
49 | /* MCS rates are used only with 11n */ | |
50 | 15, /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */ | |
51 | 14, /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */ | |
52 | 13, /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */ | |
53 | 12, /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */ | |
54 | 11, /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */ | |
55 | 10, /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */ | |
56 | 9, /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */ | |
57 | 8, /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */ | |
58 | 7, /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */ | |
59 | 6, /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */ | |
60 | 5, /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */ | |
61 | 4, /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */ | |
62 | 3, /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */ | |
63 | 2, /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */ | |
64 | 1, /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */ | |
65 | 0, /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */ | |
66 | ||
67 | 11, /* WL18XX_CONF_HW_RXTX_RATE_54 */ | |
68 | 10, /* WL18XX_CONF_HW_RXTX_RATE_48 */ | |
69 | 9, /* WL18XX_CONF_HW_RXTX_RATE_36 */ | |
70 | 8, /* WL18XX_CONF_HW_RXTX_RATE_24 */ | |
71 | ||
72 | /* TI-specific rate */ | |
73 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22 */ | |
74 | ||
75 | 7, /* WL18XX_CONF_HW_RXTX_RATE_18 */ | |
76 | 6, /* WL18XX_CONF_HW_RXTX_RATE_12 */ | |
77 | 3, /* WL18XX_CONF_HW_RXTX_RATE_11 */ | |
78 | 5, /* WL18XX_CONF_HW_RXTX_RATE_9 */ | |
79 | 4, /* WL18XX_CONF_HW_RXTX_RATE_6 */ | |
80 | 2, /* WL18XX_CONF_HW_RXTX_RATE_5_5 */ | |
81 | 1, /* WL18XX_CONF_HW_RXTX_RATE_2 */ | |
82 | 0 /* WL18XX_CONF_HW_RXTX_RATE_1 */ | |
83 | }; | |
84 | ||
85 | static const u8 wl18xx_rate_to_idx_5ghz[] = { | |
86 | /* MCS rates are used only with 11n */ | |
87 | 15, /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */ | |
88 | 14, /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */ | |
89 | 13, /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */ | |
90 | 12, /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */ | |
91 | 11, /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */ | |
92 | 10, /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */ | |
93 | 9, /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */ | |
94 | 8, /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */ | |
95 | 7, /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */ | |
96 | 6, /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */ | |
97 | 5, /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */ | |
98 | 4, /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */ | |
99 | 3, /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */ | |
100 | 2, /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */ | |
101 | 1, /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */ | |
102 | 0, /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */ | |
103 | ||
104 | 7, /* WL18XX_CONF_HW_RXTX_RATE_54 */ | |
105 | 6, /* WL18XX_CONF_HW_RXTX_RATE_48 */ | |
106 | 5, /* WL18XX_CONF_HW_RXTX_RATE_36 */ | |
107 | 4, /* WL18XX_CONF_HW_RXTX_RATE_24 */ | |
108 | ||
109 | /* TI-specific rate */ | |
110 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22 */ | |
111 | ||
112 | 3, /* WL18XX_CONF_HW_RXTX_RATE_18 */ | |
113 | 2, /* WL18XX_CONF_HW_RXTX_RATE_12 */ | |
114 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_11 */ | |
115 | 1, /* WL18XX_CONF_HW_RXTX_RATE_9 */ | |
116 | 0, /* WL18XX_CONF_HW_RXTX_RATE_6 */ | |
117 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_5_5 */ | |
118 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_2 */ | |
119 | CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_1 */ | |
120 | }; | |
121 | ||
122 | static const u8 *wl18xx_band_rate_to_idx[] = { | |
123 | [IEEE80211_BAND_2GHZ] = wl18xx_rate_to_idx_2ghz, | |
124 | [IEEE80211_BAND_5GHZ] = wl18xx_rate_to_idx_5ghz | |
125 | }; | |
126 | ||
127 | enum wl18xx_hw_rates { | |
128 | WL18XX_CONF_HW_RXTX_RATE_MCS15 = 0, | |
129 | WL18XX_CONF_HW_RXTX_RATE_MCS14, | |
130 | WL18XX_CONF_HW_RXTX_RATE_MCS13, | |
131 | WL18XX_CONF_HW_RXTX_RATE_MCS12, | |
132 | WL18XX_CONF_HW_RXTX_RATE_MCS11, | |
133 | WL18XX_CONF_HW_RXTX_RATE_MCS10, | |
134 | WL18XX_CONF_HW_RXTX_RATE_MCS9, | |
135 | WL18XX_CONF_HW_RXTX_RATE_MCS8, | |
136 | WL18XX_CONF_HW_RXTX_RATE_MCS7, | |
137 | WL18XX_CONF_HW_RXTX_RATE_MCS6, | |
138 | WL18XX_CONF_HW_RXTX_RATE_MCS5, | |
139 | WL18XX_CONF_HW_RXTX_RATE_MCS4, | |
140 | WL18XX_CONF_HW_RXTX_RATE_MCS3, | |
141 | WL18XX_CONF_HW_RXTX_RATE_MCS2, | |
142 | WL18XX_CONF_HW_RXTX_RATE_MCS1, | |
143 | WL18XX_CONF_HW_RXTX_RATE_MCS0, | |
144 | WL18XX_CONF_HW_RXTX_RATE_54, | |
145 | WL18XX_CONF_HW_RXTX_RATE_48, | |
146 | WL18XX_CONF_HW_RXTX_RATE_36, | |
147 | WL18XX_CONF_HW_RXTX_RATE_24, | |
148 | WL18XX_CONF_HW_RXTX_RATE_22, | |
149 | WL18XX_CONF_HW_RXTX_RATE_18, | |
150 | WL18XX_CONF_HW_RXTX_RATE_12, | |
151 | WL18XX_CONF_HW_RXTX_RATE_11, | |
152 | WL18XX_CONF_HW_RXTX_RATE_9, | |
153 | WL18XX_CONF_HW_RXTX_RATE_6, | |
154 | WL18XX_CONF_HW_RXTX_RATE_5_5, | |
155 | WL18XX_CONF_HW_RXTX_RATE_2, | |
156 | WL18XX_CONF_HW_RXTX_RATE_1, | |
157 | WL18XX_CONF_HW_RXTX_RATE_MAX, | |
158 | }; | |
159 | ||
23ee9bf8 LC |
160 | static struct wlcore_conf wl18xx_conf = { |
161 | .sg = { | |
162 | .params = { | |
163 | [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, | |
164 | [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, | |
165 | [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, | |
166 | [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, | |
167 | [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, | |
168 | [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, | |
169 | [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, | |
170 | [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, | |
171 | [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, | |
172 | [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, | |
173 | [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, | |
174 | [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, | |
175 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, | |
176 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, | |
177 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, | |
178 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, | |
179 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, | |
180 | [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, | |
181 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, | |
182 | [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, | |
183 | [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, | |
184 | [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, | |
185 | [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, | |
186 | [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, | |
187 | [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, | |
188 | [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, | |
189 | /* active scan params */ | |
190 | [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, | |
191 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, | |
192 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, | |
193 | /* passive scan params */ | |
194 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, | |
195 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, | |
196 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, | |
197 | /* passive scan in dual antenna params */ | |
198 | [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, | |
199 | [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, | |
200 | [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, | |
201 | /* general params */ | |
202 | [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, | |
203 | [CONF_SG_ANTENNA_CONFIGURATION] = 0, | |
204 | [CONF_SG_BEACON_MISS_PERCENT] = 60, | |
205 | [CONF_SG_DHCP_TIME] = 5000, | |
206 | [CONF_SG_RXT] = 1200, | |
207 | [CONF_SG_TXT] = 1000, | |
208 | [CONF_SG_ADAPTIVE_RXT_TXT] = 1, | |
209 | [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, | |
210 | [CONF_SG_HV3_MAX_SERVED] = 6, | |
211 | [CONF_SG_PS_POLL_TIMEOUT] = 10, | |
212 | [CONF_SG_UPSD_TIMEOUT] = 10, | |
213 | [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, | |
214 | [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, | |
215 | [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, | |
216 | /* AP params */ | |
217 | [CONF_AP_BEACON_MISS_TX] = 3, | |
218 | [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, | |
219 | [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, | |
220 | [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, | |
221 | [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, | |
222 | [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, | |
223 | /* CTS Diluting params */ | |
224 | [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, | |
225 | [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, | |
226 | }, | |
227 | .state = CONF_SG_PROTECTIVE, | |
228 | }, | |
229 | .rx = { | |
230 | .rx_msdu_life_time = 512000, | |
231 | .packet_detection_threshold = 0, | |
232 | .ps_poll_timeout = 15, | |
233 | .upsd_timeout = 15, | |
234 | .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, | |
235 | .rx_cca_threshold = 0, | |
236 | .irq_blk_threshold = 0xFFFF, | |
237 | .irq_pkt_threshold = 0, | |
238 | .irq_timeout = 600, | |
239 | .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, | |
240 | }, | |
241 | .tx = { | |
242 | .tx_energy_detection = 0, | |
243 | .sta_rc_conf = { | |
244 | .enabled_rates = 0, | |
245 | .short_retry_limit = 10, | |
246 | .long_retry_limit = 10, | |
247 | .aflags = 0, | |
248 | }, | |
249 | .ac_conf_count = 4, | |
250 | .ac_conf = { | |
251 | [CONF_TX_AC_BE] = { | |
252 | .ac = CONF_TX_AC_BE, | |
253 | .cw_min = 15, | |
254 | .cw_max = 63, | |
255 | .aifsn = 3, | |
256 | .tx_op_limit = 0, | |
257 | }, | |
258 | [CONF_TX_AC_BK] = { | |
259 | .ac = CONF_TX_AC_BK, | |
260 | .cw_min = 15, | |
261 | .cw_max = 63, | |
262 | .aifsn = 7, | |
263 | .tx_op_limit = 0, | |
264 | }, | |
265 | [CONF_TX_AC_VI] = { | |
266 | .ac = CONF_TX_AC_VI, | |
267 | .cw_min = 15, | |
268 | .cw_max = 63, | |
269 | .aifsn = CONF_TX_AIFS_PIFS, | |
270 | .tx_op_limit = 3008, | |
271 | }, | |
272 | [CONF_TX_AC_VO] = { | |
273 | .ac = CONF_TX_AC_VO, | |
274 | .cw_min = 15, | |
275 | .cw_max = 63, | |
276 | .aifsn = CONF_TX_AIFS_PIFS, | |
277 | .tx_op_limit = 1504, | |
278 | }, | |
279 | }, | |
280 | .max_tx_retries = 100, | |
281 | .ap_aging_period = 300, | |
282 | .tid_conf_count = 4, | |
283 | .tid_conf = { | |
284 | [CONF_TX_AC_BE] = { | |
285 | .queue_id = CONF_TX_AC_BE, | |
286 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | |
287 | .tsid = CONF_TX_AC_BE, | |
288 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | |
289 | .ack_policy = CONF_ACK_POLICY_LEGACY, | |
290 | .apsd_conf = {0, 0}, | |
291 | }, | |
292 | [CONF_TX_AC_BK] = { | |
293 | .queue_id = CONF_TX_AC_BK, | |
294 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | |
295 | .tsid = CONF_TX_AC_BK, | |
296 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | |
297 | .ack_policy = CONF_ACK_POLICY_LEGACY, | |
298 | .apsd_conf = {0, 0}, | |
299 | }, | |
300 | [CONF_TX_AC_VI] = { | |
301 | .queue_id = CONF_TX_AC_VI, | |
302 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | |
303 | .tsid = CONF_TX_AC_VI, | |
304 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | |
305 | .ack_policy = CONF_ACK_POLICY_LEGACY, | |
306 | .apsd_conf = {0, 0}, | |
307 | }, | |
308 | [CONF_TX_AC_VO] = { | |
309 | .queue_id = CONF_TX_AC_VO, | |
310 | .channel_type = CONF_CHANNEL_TYPE_EDCF, | |
311 | .tsid = CONF_TX_AC_VO, | |
312 | .ps_scheme = CONF_PS_SCHEME_LEGACY, | |
313 | .ack_policy = CONF_ACK_POLICY_LEGACY, | |
314 | .apsd_conf = {0, 0}, | |
315 | }, | |
316 | }, | |
317 | .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, | |
318 | .tx_compl_timeout = 350, | |
319 | .tx_compl_threshold = 10, | |
320 | .basic_rate = CONF_HW_BIT_RATE_1MBPS, | |
321 | .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, | |
322 | .tmpl_short_retry_limit = 10, | |
323 | .tmpl_long_retry_limit = 10, | |
324 | .tx_watchdog_timeout = 5000, | |
325 | }, | |
326 | .conn = { | |
327 | .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, | |
328 | .listen_interval = 1, | |
329 | .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, | |
330 | .suspend_listen_interval = 3, | |
331 | .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, | |
332 | .bcn_filt_ie_count = 2, | |
333 | .bcn_filt_ie = { | |
334 | [0] = { | |
335 | .ie = WLAN_EID_CHANNEL_SWITCH, | |
336 | .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, | |
337 | }, | |
338 | [1] = { | |
339 | .ie = WLAN_EID_HT_OPERATION, | |
340 | .rule = CONF_BCN_RULE_PASS_ON_CHANGE, | |
341 | }, | |
342 | }, | |
343 | .synch_fail_thold = 10, | |
344 | .bss_lose_timeout = 100, | |
345 | .beacon_rx_timeout = 10000, | |
346 | .broadcast_timeout = 20000, | |
347 | .rx_broadcast_in_ps = 1, | |
348 | .ps_poll_threshold = 10, | |
349 | .bet_enable = CONF_BET_MODE_ENABLE, | |
350 | .bet_max_consecutive = 50, | |
351 | .psm_entry_retries = 8, | |
352 | .psm_exit_retries = 16, | |
353 | .psm_entry_nullfunc_retries = 3, | |
354 | .dynamic_ps_timeout = 40, | |
355 | .forced_ps = false, | |
356 | .keep_alive_interval = 55000, | |
357 | .max_listen_interval = 20, | |
358 | }, | |
359 | .itrim = { | |
360 | .enable = false, | |
361 | .timeout = 50000, | |
362 | }, | |
363 | .pm_config = { | |
364 | .host_clk_settling_time = 5000, | |
365 | .host_fast_wakeup_support = false | |
366 | }, | |
367 | .roam_trigger = { | |
368 | .trigger_pacing = 1, | |
369 | .avg_weight_rssi_beacon = 20, | |
370 | .avg_weight_rssi_data = 10, | |
371 | .avg_weight_snr_beacon = 20, | |
372 | .avg_weight_snr_data = 10, | |
373 | }, | |
374 | .scan = { | |
375 | .min_dwell_time_active = 7500, | |
376 | .max_dwell_time_active = 30000, | |
377 | .min_dwell_time_passive = 100000, | |
378 | .max_dwell_time_passive = 100000, | |
379 | .num_probe_reqs = 2, | |
380 | .split_scan_timeout = 50000, | |
381 | }, | |
382 | .sched_scan = { | |
383 | /* | |
384 | * Values are in TU/1000 but since sched scan FW command | |
385 | * params are in TUs rounding up may occur. | |
386 | */ | |
387 | .base_dwell_time = 7500, | |
388 | .max_dwell_time_delta = 22500, | |
389 | /* based on 250bits per probe @1Mbps */ | |
390 | .dwell_time_delta_per_probe = 2000, | |
391 | /* based on 250bits per probe @6Mbps (plus a bit more) */ | |
392 | .dwell_time_delta_per_probe_5 = 350, | |
393 | .dwell_time_passive = 100000, | |
394 | .dwell_time_dfs = 150000, | |
395 | .num_probe_reqs = 2, | |
396 | .rssi_threshold = -90, | |
397 | .snr_threshold = 0, | |
398 | }, | |
399 | .ht = { | |
400 | .rx_ba_win_size = 10, | |
401 | .tx_ba_win_size = 10, | |
402 | .inactivity_timeout = 10000, | |
403 | .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, | |
404 | }, | |
405 | .mem = { | |
406 | .num_stations = 1, | |
407 | .ssid_profiles = 1, | |
408 | .rx_block_num = 40, | |
409 | .tx_min_block_num = 40, | |
410 | .dynamic_memory = 1, | |
411 | .min_req_tx_blocks = 45, | |
412 | .min_req_rx_blocks = 22, | |
413 | .tx_min = 27, | |
414 | }, | |
415 | .fm_coex = { | |
416 | .enable = true, | |
417 | .swallow_period = 5, | |
418 | .n_divider_fref_set_1 = 0xff, /* default */ | |
419 | .n_divider_fref_set_2 = 12, | |
420 | .m_divider_fref_set_1 = 148, | |
421 | .m_divider_fref_set_2 = 0xffff, /* default */ | |
422 | .coex_pll_stabilization_time = 0xffffffff, /* default */ | |
423 | .ldo_stabilization_time = 0xffff, /* default */ | |
424 | .fm_disturbed_band_margin = 0xff, /* default */ | |
425 | .swallow_clk_diff = 0xff, /* default */ | |
426 | }, | |
427 | .rx_streaming = { | |
428 | .duration = 150, | |
429 | .queues = 0x1, | |
430 | .interval = 20, | |
431 | .always = 0, | |
432 | }, | |
433 | .fwlog = { | |
434 | .mode = WL12XX_FWLOG_ON_DEMAND, | |
435 | .mem_blocks = 2, | |
436 | .severity = 0, | |
437 | .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, | |
438 | .output = WL12XX_FWLOG_OUTPUT_HOST, | |
439 | .threshold = 0, | |
440 | }, | |
441 | .rate = { | |
442 | .rate_retry_score = 32000, | |
443 | .per_add = 8192, | |
444 | .per_th1 = 2048, | |
445 | .per_th2 = 4096, | |
446 | .max_per = 8100, | |
447 | .inverse_curiosity_factor = 5, | |
448 | .tx_fail_low_th = 4, | |
449 | .tx_fail_high_th = 10, | |
450 | .per_alpha_shift = 4, | |
451 | .per_add_shift = 13, | |
452 | .per_beta1_shift = 10, | |
453 | .per_beta2_shift = 8, | |
454 | .rate_check_up = 2, | |
455 | .rate_check_down = 12, | |
456 | .rate_retry_policy = { | |
457 | 0x00, 0x00, 0x00, 0x00, 0x00, | |
458 | 0x00, 0x00, 0x00, 0x00, 0x00, | |
459 | 0x00, 0x00, 0x00, | |
460 | }, | |
461 | }, | |
462 | .hangover = { | |
463 | .recover_time = 0, | |
464 | .hangover_period = 20, | |
465 | .dynamic_mode = 1, | |
466 | .early_termination_mode = 1, | |
467 | .max_period = 20, | |
468 | .min_period = 1, | |
469 | .increase_delta = 1, | |
470 | .decrease_delta = 2, | |
471 | .quiet_time = 4, | |
472 | .increase_time = 1, | |
473 | .window_size = 16, | |
474 | }, | |
475 | }; | |
476 | ||
477 | static struct wl18xx_priv_conf wl18xx_default_priv_conf = { | |
46a1d512 LC |
478 | .phy = { |
479 | .phy_standalone = 0x00, | |
480 | .primary_clock_setting_time = 0x05, | |
481 | .clock_valid_on_wake_up = 0x00, | |
482 | .secondary_clock_setting_time = 0x05, | |
483 | .rdl = 0x01, | |
484 | .auto_detect = 0x00, | |
485 | .dedicated_fem = FEM_NONE, | |
486 | .low_band_component = COMPONENT_2_WAY_SWITCH, | |
487 | .low_band_component_type = 0x05, | |
488 | .high_band_component = COMPONENT_2_WAY_SWITCH, | |
489 | .high_band_component_type = 0x09, | |
490 | .number_of_assembled_ant2_4 = 0x01, | |
491 | .number_of_assembled_ant5 = 0x01, | |
492 | .external_pa_dc2dc = 0x00, | |
493 | .tcxo_ldo_voltage = 0x00, | |
494 | .xtal_itrim_val = 0x04, | |
495 | .srf_state = 0x00, | |
496 | .io_configuration = 0x01, | |
497 | .sdio_configuration = 0x00, | |
498 | .settings = 0x00, | |
499 | .enable_clpc = 0x00, | |
500 | .enable_tx_low_pwr_on_siso_rdl = 0x00, | |
501 | .rx_profile = 0x00, | |
502 | }, | |
503 | }; | |
5d4a9fa6 | 504 | |
82b890cd LC |
505 | static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = { |
506 | [PART_TOP_PRCM_ELP_SOC] = { | |
507 | .mem = { .start = 0x00A02000, .size = 0x00010000 }, | |
508 | .reg = { .start = 0x00807000, .size = 0x00005000 }, | |
509 | .mem2 = { .start = 0x00800000, .size = 0x0000B000 }, | |
510 | .mem3 = { .start = 0x00000000, .size = 0x00000000 }, | |
511 | }, | |
512 | [PART_DOWN] = { | |
513 | .mem = { .start = 0x00000000, .size = 0x00014000 }, | |
514 | .reg = { .start = 0x00810000, .size = 0x0000BFFF }, | |
515 | .mem2 = { .start = 0x00000000, .size = 0x00000000 }, | |
516 | .mem3 = { .start = 0x00000000, .size = 0x00000000 }, | |
517 | }, | |
518 | [PART_BOOT] = { | |
519 | .mem = { .start = 0x00700000, .size = 0x0000030c }, | |
520 | .reg = { .start = 0x00802000, .size = 0x00014578 }, | |
521 | .mem2 = { .start = 0x00B00404, .size = 0x00001000 }, | |
522 | .mem3 = { .start = 0x00C00000, .size = 0x00000400 }, | |
523 | }, | |
524 | [PART_WORK] = { | |
525 | .mem = { .start = 0x00800000, .size = 0x000050FC }, | |
526 | .reg = { .start = 0x00B00404, .size = 0x00001000 }, | |
527 | .mem2 = { .start = 0x00C00000, .size = 0x00000400 }, | |
528 | .mem3 = { .start = 0x00000000, .size = 0x00000000 }, | |
529 | }, | |
530 | [PART_PHY_INIT] = { | |
531 | /* TODO: use the phy_conf struct size here */ | |
532 | .mem = { .start = 0x80926000, .size = 252 }, | |
533 | .reg = { .start = 0x00000000, .size = 0x00000000 }, | |
534 | .mem2 = { .start = 0x00000000, .size = 0x00000000 }, | |
535 | .mem3 = { .start = 0x00000000, .size = 0x00000000 }, | |
536 | }, | |
537 | }; | |
538 | ||
5d4a9fa6 LC |
539 | static const int wl18xx_rtable[REG_TABLE_LEN] = { |
540 | [REG_ECPU_CONTROL] = WL18XX_REG_ECPU_CONTROL, | |
541 | [REG_INTERRUPT_NO_CLEAR] = WL18XX_REG_INTERRUPT_NO_CLEAR, | |
542 | [REG_INTERRUPT_ACK] = WL18XX_REG_INTERRUPT_ACK, | |
543 | [REG_COMMAND_MAILBOX_PTR] = WL18XX_REG_COMMAND_MAILBOX_PTR, | |
544 | [REG_EVENT_MAILBOX_PTR] = WL18XX_REG_EVENT_MAILBOX_PTR, | |
545 | [REG_INTERRUPT_TRIG] = WL18XX_REG_INTERRUPT_TRIG_H, | |
546 | [REG_INTERRUPT_MASK] = WL18XX_REG_INTERRUPT_MASK, | |
1c351da6 | 547 | [REG_PC_ON_RECOVERY] = WL18XX_SCR_PAD4, |
5d4a9fa6 LC |
548 | [REG_CHIP_ID_B] = WL18XX_REG_CHIP_ID_B, |
549 | [REG_CMD_MBOX_ADDRESS] = WL18XX_CMD_MBOX_ADDRESS, | |
550 | ||
551 | /* data access memory addresses, used with partition translation */ | |
552 | [REG_SLV_MEM_DATA] = WL18XX_SLV_MEM_DATA, | |
553 | [REG_SLV_REG_DATA] = WL18XX_SLV_REG_DATA, | |
554 | ||
555 | /* raw data access memory addresses */ | |
556 | [REG_RAW_FW_STATUS_ADDR] = WL18XX_FW_STATUS_ADDR, | |
557 | }; | |
558 | ||
be65202a LC |
559 | static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = { |
560 | [CLOCK_CONFIG_16_2_M] = { 7, 104, 801, 4, true }, | |
561 | [CLOCK_CONFIG_16_368_M] = { 9, 132, 3751, 4, true }, | |
562 | [CLOCK_CONFIG_16_8_M] = { 7, 100, 0, 0, false }, | |
563 | [CLOCK_CONFIG_19_2_M] = { 8, 100, 0, 0, false }, | |
564 | [CLOCK_CONFIG_26_M] = { 13, 120, 0, 0, false }, | |
565 | [CLOCK_CONFIG_32_736_M] = { 9, 132, 3751, 4, true }, | |
566 | [CLOCK_CONFIG_33_6_M] = { 7, 100, 0, 0, false }, | |
567 | [CLOCK_CONFIG_38_468_M] = { 8, 100, 0, 0, false }, | |
568 | [CLOCK_CONFIG_52_M] = { 13, 120, 0, 0, false }, | |
569 | }; | |
570 | ||
0cd6543f LC |
571 | /* TODO: maybe move to a new header file? */ |
572 | #define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw.bin" | |
573 | ||
574 | static int wl18xx_identify_chip(struct wl1271 *wl) | |
575 | { | |
576 | int ret = 0; | |
577 | ||
578 | switch (wl->chip.id) { | |
579 | case CHIP_ID_185x_PG10: | |
580 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)", | |
581 | wl->chip.id); | |
582 | wl->sr_fw_name = WL18XX_FW_NAME; | |
be42aee6 LC |
583 | /* wl18xx uses the same firmware for PLT */ |
584 | wl->plt_fw_name = WL18XX_FW_NAME; | |
7cfefd1f | 585 | wl->quirks |= WLCORE_QUIRK_NO_ELP | |
d9fedea2 | 586 | WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED | |
7cfefd1f | 587 | WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN; |
0cd6543f LC |
588 | |
589 | /* TODO: need to blocksize alignment for RX/TX separately? */ | |
590 | break; | |
591 | default: | |
592 | wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); | |
593 | ret = -ENODEV; | |
594 | goto out; | |
595 | } | |
596 | ||
597 | out: | |
598 | return ret; | |
599 | } | |
600 | ||
46a1d512 LC |
601 | static void wl18xx_set_clk(struct wl1271 *wl) |
602 | { | |
be65202a | 603 | u32 clk_freq; |
d5b59276 | 604 | |
46a1d512 | 605 | wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); |
be65202a LC |
606 | |
607 | /* TODO: PG2: apparently we need to read the clk type */ | |
608 | ||
609 | clk_freq = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT); | |
610 | wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq, | |
611 | wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m, | |
612 | wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q, | |
613 | wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit"); | |
614 | ||
615 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, wl18xx_clk_table[clk_freq].n); | |
616 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M, wl18xx_clk_table[clk_freq].m); | |
617 | ||
618 | if (wl18xx_clk_table[clk_freq].swallow) { | |
619 | /* first the 16 lower bits */ | |
620 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1, | |
621 | wl18xx_clk_table[clk_freq].q & | |
622 | PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK); | |
623 | /* then the 16 higher bits, masked out */ | |
624 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2, | |
625 | (wl18xx_clk_table[clk_freq].q >> 16) & | |
626 | PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK); | |
627 | ||
628 | /* first the 16 lower bits */ | |
629 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1, | |
630 | wl18xx_clk_table[clk_freq].p & | |
631 | PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK); | |
632 | /* then the 16 higher bits, masked out */ | |
633 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2, | |
634 | (wl18xx_clk_table[clk_freq].p >> 16) & | |
635 | PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK); | |
636 | } else { | |
637 | wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN, | |
638 | PLLSH_WCS_PLL_SWALLOW_EN_VAL2); | |
639 | } | |
46a1d512 LC |
640 | } |
641 | ||
642 | static void wl18xx_boot_soft_reset(struct wl1271 *wl) | |
643 | { | |
644 | /* disable Rx/Tx */ | |
645 | wl1271_write32(wl, WL18XX_ENABLE, 0x0); | |
646 | ||
647 | /* disable auto calibration on start*/ | |
648 | wl1271_write32(wl, WL18XX_SPARE_A2, 0xffff); | |
649 | } | |
650 | ||
651 | static int wl18xx_pre_boot(struct wl1271 *wl) | |
652 | { | |
46a1d512 LC |
653 | wl18xx_set_clk(wl); |
654 | ||
655 | /* Continue the ELP wake up sequence */ | |
656 | wl1271_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); | |
657 | udelay(500); | |
658 | ||
659 | wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); | |
660 | ||
661 | /* Disable interrupts */ | |
662 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); | |
663 | ||
664 | wl18xx_boot_soft_reset(wl); | |
665 | ||
666 | return 0; | |
667 | } | |
668 | ||
669 | static void wl18xx_pre_upload(struct wl1271 *wl) | |
670 | { | |
671 | u32 tmp; | |
672 | ||
673 | wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); | |
674 | ||
675 | /* TODO: check if this is all needed */ | |
676 | wl1271_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND); | |
677 | ||
678 | tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); | |
679 | ||
680 | wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); | |
681 | ||
682 | tmp = wl1271_read32(wl, WL18XX_SCR_PAD2); | |
683 | } | |
684 | ||
685 | static void wl18xx_set_mac_and_phy(struct wl1271 *wl) | |
686 | { | |
23ee9bf8 LC |
687 | struct wl18xx_priv *priv = wl->priv; |
688 | struct wl18xx_conf_phy *phy = &priv->conf.phy; | |
46a1d512 LC |
689 | struct wl18xx_mac_and_phy_params params; |
690 | ||
691 | memset(¶ms, 0, sizeof(params)); | |
692 | ||
23ee9bf8 LC |
693 | params.phy_standalone = phy->phy_standalone; |
694 | params.rdl = phy->rdl; | |
695 | params.enable_clpc = phy->enable_clpc; | |
46a1d512 | 696 | params.enable_tx_low_pwr_on_siso_rdl = |
23ee9bf8 LC |
697 | phy->enable_tx_low_pwr_on_siso_rdl; |
698 | params.auto_detect = phy->auto_detect; | |
699 | params.dedicated_fem = phy->dedicated_fem; | |
700 | params.low_band_component = phy->low_band_component; | |
46a1d512 | 701 | params.low_band_component_type = |
23ee9bf8 LC |
702 | phy->low_band_component_type; |
703 | params.high_band_component = phy->high_band_component; | |
46a1d512 | 704 | params.high_band_component_type = |
23ee9bf8 | 705 | phy->high_band_component_type; |
46a1d512 | 706 | params.number_of_assembled_ant2_4 = |
23ee9bf8 | 707 | phy->number_of_assembled_ant2_4; |
46a1d512 | 708 | params.number_of_assembled_ant5 = |
23ee9bf8 LC |
709 | phy->number_of_assembled_ant5; |
710 | params.external_pa_dc2dc = phy->external_pa_dc2dc; | |
711 | params.tcxo_ldo_voltage = phy->tcxo_ldo_voltage; | |
712 | params.xtal_itrim_val = phy->xtal_itrim_val; | |
713 | params.srf_state = phy->srf_state; | |
714 | params.io_configuration = phy->io_configuration; | |
715 | params.sdio_configuration = phy->sdio_configuration; | |
716 | params.settings = phy->settings; | |
717 | params.rx_profile = phy->rx_profile; | |
46a1d512 | 718 | params.primary_clock_setting_time = |
23ee9bf8 | 719 | phy->primary_clock_setting_time; |
46a1d512 | 720 | params.clock_valid_on_wake_up = |
23ee9bf8 | 721 | phy->clock_valid_on_wake_up; |
46a1d512 | 722 | params.secondary_clock_setting_time = |
23ee9bf8 | 723 | phy->secondary_clock_setting_time; |
46a1d512 | 724 | |
a9c130d5 | 725 | params.board_type = priv->board_type; |
46a1d512 LC |
726 | |
727 | wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]); | |
728 | wl1271_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)¶ms, | |
729 | sizeof(params), false); | |
730 | } | |
731 | ||
732 | static void wl18xx_enable_interrupts(struct wl1271 *wl) | |
733 | { | |
734 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_ALL_EVENTS_VECTOR); | |
735 | ||
736 | wlcore_enable_interrupts(wl); | |
737 | wlcore_write_reg(wl, REG_INTERRUPT_MASK, | |
738 | WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK)); | |
739 | } | |
740 | ||
741 | static int wl18xx_boot(struct wl1271 *wl) | |
742 | { | |
743 | int ret; | |
744 | ||
745 | ret = wl18xx_pre_boot(wl); | |
746 | if (ret < 0) | |
747 | goto out; | |
748 | ||
46a1d512 LC |
749 | wl18xx_pre_upload(wl); |
750 | ||
751 | ret = wlcore_boot_upload_firmware(wl); | |
752 | if (ret < 0) | |
753 | goto out; | |
754 | ||
755 | wl18xx_set_mac_and_phy(wl); | |
756 | ||
757 | ret = wlcore_boot_run_firmware(wl); | |
758 | if (ret < 0) | |
759 | goto out; | |
760 | ||
761 | wl18xx_enable_interrupts(wl); | |
762 | ||
763 | out: | |
764 | return ret; | |
765 | } | |
766 | ||
274c66cd LC |
767 | static void wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, |
768 | void *buf, size_t len) | |
769 | { | |
770 | struct wl18xx_priv *priv = wl->priv; | |
771 | ||
772 | memcpy(priv->cmd_buf, buf, len); | |
773 | memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len); | |
774 | ||
775 | wl1271_write(wl, cmd_box_addr, priv->cmd_buf, WL18XX_CMD_MAX_SIZE, | |
776 | false); | |
777 | } | |
778 | ||
779 | static void wl18xx_ack_event(struct wl1271 *wl) | |
780 | { | |
781 | wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL18XX_INTR_TRIG_EVENT_ACK); | |
782 | } | |
783 | ||
624845b3 AN |
784 | static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) |
785 | { | |
786 | u32 blk_size = WL18XX_TX_HW_BLOCK_SIZE; | |
787 | return (len + blk_size - 1) / blk_size + spare_blks; | |
788 | } | |
789 | ||
fb0f2e4a AN |
790 | static void |
791 | wl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, | |
792 | u32 blks, u32 spare_blks) | |
793 | { | |
794 | desc->wl18xx_mem.total_mem_blocks = blks; | |
795 | desc->wl18xx_mem.reserved = 0; | |
796 | } | |
797 | ||
d2361c51 AN |
798 | static void |
799 | wl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, | |
800 | struct sk_buff *skb) | |
801 | { | |
802 | desc->length = cpu_to_le16(skb->len); | |
803 | ||
804 | wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " | |
805 | "len: %d life: %d mem: %d", desc->hlid, | |
806 | le16_to_cpu(desc->length), | |
807 | le16_to_cpu(desc->life_time), | |
808 | desc->wl18xx_mem.total_mem_blocks); | |
809 | } | |
810 | ||
9c809f88 AN |
811 | static enum wl_rx_buf_align |
812 | wl18xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) | |
813 | { | |
814 | if (rx_desc & RX_BUF_PADDED_PAYLOAD) | |
815 | return WLCORE_RX_BUF_PADDED; | |
816 | ||
817 | return WLCORE_RX_BUF_ALIGNED; | |
818 | } | |
819 | ||
30e2dd79 AN |
820 | static u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data, |
821 | u32 data_len) | |
822 | { | |
823 | struct wl1271_rx_descriptor *desc = rx_data; | |
824 | ||
825 | /* invalid packet */ | |
826 | if (data_len < sizeof(*desc)) | |
827 | return 0; | |
828 | ||
829 | return data_len - sizeof(*desc); | |
830 | } | |
9c809f88 | 831 | |
872b345f AN |
832 | static void wl18xx_tx_immediate_completion(struct wl1271 *wl) |
833 | { | |
834 | wl18xx_tx_immediate_complete(wl); | |
835 | } | |
836 | ||
b8422dcb LC |
837 | static int wl18xx_hw_init(struct wl1271 *wl) |
838 | { | |
839 | int ret; | |
f2baf075 | 840 | struct wl18xx_priv *priv = wl->priv; |
b8422dcb LC |
841 | u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE | |
842 | HOST_IF_CFG_ADD_RX_ALIGNMENT; | |
843 | ||
844 | u32 sdio_align_size = 0; | |
845 | ||
f2baf075 AN |
846 | /* (re)init private structures. Relevant on recovery as well. */ |
847 | priv->last_fw_rls_idx = 0; | |
848 | ||
b8422dcb LC |
849 | /* Enable Tx SDIO padding */ |
850 | if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) { | |
851 | host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; | |
852 | sdio_align_size = WL12XX_BUS_BLOCK_SIZE; | |
853 | } | |
854 | ||
855 | /* Enable Rx SDIO padding */ | |
856 | if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) { | |
857 | host_cfg_bitmap |= HOST_IF_CFG_RX_PAD_TO_SDIO_BLK; | |
858 | sdio_align_size = WL12XX_BUS_BLOCK_SIZE; | |
859 | } | |
860 | ||
861 | ret = wl18xx_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap, | |
862 | sdio_align_size, | |
863 | WL18XX_TX_HW_BLOCK_SPARE, | |
864 | WL18XX_HOST_IF_LEN_SIZE_FIELD); | |
865 | if (ret < 0) | |
866 | return ret; | |
867 | ||
2fc28de5 AN |
868 | ret = wl18xx_acx_set_checksum_state(wl); |
869 | if (ret != 0) | |
870 | return ret; | |
871 | ||
b8422dcb LC |
872 | return ret; |
873 | } | |
874 | ||
2fc28de5 AN |
875 | static void wl18xx_set_tx_desc_csum(struct wl1271 *wl, |
876 | struct wl1271_tx_hw_descr *desc, | |
877 | struct sk_buff *skb) | |
878 | { | |
879 | u32 ip_hdr_offset; | |
880 | struct iphdr *ip_hdr; | |
881 | ||
882 | if (skb->ip_summed != CHECKSUM_PARTIAL) { | |
883 | desc->wl18xx_checksum_data = 0; | |
884 | return; | |
885 | } | |
886 | ||
887 | ip_hdr_offset = skb_network_header(skb) - skb_mac_header(skb); | |
888 | if (WARN_ON(ip_hdr_offset >= (1<<7))) { | |
889 | desc->wl18xx_checksum_data = 0; | |
890 | return; | |
891 | } | |
892 | ||
893 | desc->wl18xx_checksum_data = ip_hdr_offset << 1; | |
894 | ||
895 | /* FW is interested only in the LSB of the protocol TCP=0 UDP=1 */ | |
896 | ip_hdr = (void *)skb_network_header(skb); | |
897 | desc->wl18xx_checksum_data |= (ip_hdr->protocol & 0x01); | |
898 | } | |
899 | ||
169da04f AN |
900 | static void wl18xx_set_rx_csum(struct wl1271 *wl, |
901 | struct wl1271_rx_descriptor *desc, | |
902 | struct sk_buff *skb) | |
903 | { | |
904 | if (desc->status & WL18XX_RX_CHECKSUM_MASK) | |
905 | skb->ip_summed = CHECKSUM_UNNECESSARY; | |
906 | } | |
907 | ||
f13af348 AN |
908 | static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl, |
909 | struct wl12xx_vif *wlvif) | |
910 | { | |
911 | u32 hw_rate_set = wlvif->rate_set; | |
912 | ||
913 | if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || | |
914 | wlvif->channel_type == NL80211_CHAN_HT40PLUS) { | |
915 | wl1271_debug(DEBUG_ACX, "using wide channel rate mask"); | |
916 | hw_rate_set |= CONF_TX_RATE_USE_WIDE_CHAN; | |
917 | ||
918 | /* we don't support MIMO in wide-channel mode */ | |
919 | hw_rate_set &= ~CONF_TX_MIMO_RATES; | |
920 | } | |
921 | ||
922 | return hw_rate_set; | |
923 | } | |
924 | ||
ebc7e57d AN |
925 | static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, |
926 | struct wl12xx_vif *wlvif) | |
927 | { | |
928 | if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || | |
929 | wlvif->channel_type == NL80211_CHAN_HT40PLUS) { | |
930 | wl1271_debug(DEBUG_ACX, "using wide channel rate mask"); | |
931 | return CONF_TX_RATE_USE_WIDE_CHAN; | |
932 | } else { | |
933 | wl1271_debug(DEBUG_ACX, "using MIMO rate mask"); | |
934 | return CONF_TX_MIMO_RATES; | |
935 | } | |
936 | } | |
937 | ||
54956294 AN |
938 | static s8 wl18xx_get_pg_ver(struct wl1271 *wl) |
939 | { | |
940 | u32 fuse; | |
941 | ||
942 | wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); | |
943 | ||
944 | fuse = wl1271_read32(wl, WL18XX_REG_FUSE_DATA_1_3); | |
945 | fuse = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; | |
946 | ||
947 | wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); | |
948 | ||
949 | return (s8)fuse; | |
950 | } | |
951 | ||
23ee9bf8 LC |
952 | static void wl18xx_conf_init(struct wl1271 *wl) |
953 | { | |
954 | struct wl18xx_priv *priv = wl->priv; | |
955 | ||
956 | /* apply driver default configuration */ | |
957 | memcpy(&wl->conf, &wl18xx_conf, sizeof(wl18xx_conf)); | |
958 | ||
959 | /* apply default private configuration */ | |
960 | memcpy(&priv->conf, &wl18xx_default_priv_conf, sizeof(priv->conf)); | |
961 | } | |
962 | ||
be42aee6 LC |
963 | static int wl18xx_plt_init(struct wl1271 *wl) |
964 | { | |
965 | wl1271_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT); | |
966 | ||
967 | return wl->ops->boot(wl); | |
968 | } | |
969 | ||
0cd6543f | 970 | static struct wlcore_ops wl18xx_ops = { |
46a1d512 LC |
971 | .identify_chip = wl18xx_identify_chip, |
972 | .boot = wl18xx_boot, | |
be42aee6 | 973 | .plt_init = wl18xx_plt_init, |
274c66cd LC |
974 | .trigger_cmd = wl18xx_trigger_cmd, |
975 | .ack_event = wl18xx_ack_event, | |
624845b3 | 976 | .calc_tx_blocks = wl18xx_calc_tx_blocks, |
fb0f2e4a | 977 | .set_tx_desc_blocks = wl18xx_set_tx_desc_blocks, |
d2361c51 | 978 | .set_tx_desc_data_len = wl18xx_set_tx_desc_data_len, |
9c809f88 | 979 | .get_rx_buf_align = wl18xx_get_rx_buf_align, |
30e2dd79 | 980 | .get_rx_packet_len = wl18xx_get_rx_packet_len, |
872b345f AN |
981 | .tx_immediate_compl = wl18xx_tx_immediate_completion, |
982 | .tx_delayed_compl = NULL, | |
b8422dcb | 983 | .hw_init = wl18xx_hw_init, |
2fc28de5 | 984 | .set_tx_desc_csum = wl18xx_set_tx_desc_csum, |
54956294 | 985 | .get_pg_ver = wl18xx_get_pg_ver, |
169da04f | 986 | .set_rx_csum = wl18xx_set_rx_csum, |
f13af348 | 987 | .sta_get_ap_rate_mask = wl18xx_sta_get_ap_rate_mask, |
ebc7e57d | 988 | .ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask, |
0cd6543f LC |
989 | }; |
990 | ||
0e0f5a3b AN |
991 | /* HT cap appropriate for wide channels */ |
992 | static struct ieee80211_sta_ht_cap wl18xx_ht_cap = { | |
993 | .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | | |
994 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40, | |
995 | .ht_supported = true, | |
996 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | |
997 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | |
998 | .mcs = { | |
999 | .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, | |
1000 | .rx_highest = cpu_to_le16(150), | |
1001 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | |
1002 | }, | |
1003 | }; | |
1004 | ||
3a8ddb61 AN |
1005 | /* HT cap appropriate for MIMO rates in 20mhz channel */ |
1006 | static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap = { | |
1007 | .cap = IEEE80211_HT_CAP_SGI_20, | |
1008 | .ht_supported = true, | |
1009 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, | |
1010 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, | |
1011 | .mcs = { | |
1012 | .rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, }, | |
1013 | .rx_highest = cpu_to_le16(144), | |
1014 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | |
1015 | }, | |
1016 | }; | |
1017 | ||
9a1a6990 LC |
1018 | int __devinit wl18xx_probe(struct platform_device *pdev) |
1019 | { | |
1020 | struct wl1271 *wl; | |
1021 | struct ieee80211_hw *hw; | |
9d1c973a | 1022 | struct wl18xx_priv *priv; |
9a1a6990 | 1023 | |
9d1c973a | 1024 | hw = wlcore_alloc_hw(sizeof(*priv)); |
9a1a6990 LC |
1025 | if (IS_ERR(hw)) { |
1026 | wl1271_error("can't allocate hw"); | |
1027 | return PTR_ERR(hw); | |
1028 | } | |
1029 | ||
1030 | wl = hw->priv; | |
a9c130d5 | 1031 | priv = wl->priv; |
554c36b7 | 1032 | wl->ops = &wl18xx_ops; |
82b890cd | 1033 | wl->ptable = wl18xx_ptable; |
5d4a9fa6 | 1034 | wl->rtable = wl18xx_rtable; |
cb7b5d86 | 1035 | wl->num_tx_desc = 32; |
1349c421 AN |
1036 | wl->normal_tx_spare = WL18XX_TX_HW_BLOCK_SPARE; |
1037 | wl->gem_tx_spare = WL18XX_TX_HW_GEM_BLOCK_SPARE; | |
f648eab7 AN |
1038 | wl->band_rate_to_idx = wl18xx_band_rate_to_idx; |
1039 | wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX; | |
1040 | wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0; | |
1fab39dc | 1041 | wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv); |
0e0f5a3b | 1042 | memcpy(&wl->ht_cap, &wl18xx_ht_cap, sizeof(wl18xx_ht_cap)); |
3a8ddb61 AN |
1043 | if (ht_mode_param && !strcmp(ht_mode_param, "mimo")) |
1044 | memcpy(&wl->ht_cap, &wl18xx_mimo_ht_cap, | |
1045 | sizeof(wl18xx_mimo_ht_cap)); | |
1046 | ||
a9c130d5 | 1047 | if (!board_type_param) { |
05057c06 AN |
1048 | board_type_param = kstrdup("dvp", GFP_KERNEL); |
1049 | priv->board_type = BOARD_TYPE_DVP_18XX; | |
1050 | } else if (!strcmp(board_type_param, "fpga")) { | |
1051 | priv->board_type = BOARD_TYPE_FPGA_18XX; | |
1052 | } else if (!strcmp(board_type_param, "hdk")) { | |
1053 | priv->board_type = BOARD_TYPE_HDK_18XX; | |
0a1569f8 LC |
1054 | /* HACK! Just for now we hardcode HDK to 0x06 */ |
1055 | priv->conf.phy.low_band_component_type = 0x06; | |
05057c06 AN |
1056 | } else if (!strcmp(board_type_param, "dvp")) { |
1057 | priv->board_type = BOARD_TYPE_DVP_18XX; | |
1058 | } else if (!strcmp(board_type_param, "evb")) { | |
1059 | priv->board_type = BOARD_TYPE_EVB_18XX; | |
1060 | } else if (!strcmp(board_type_param, "com8")) { | |
1061 | priv->board_type = BOARD_TYPE_COM8_18XX; | |
a9c130d5 | 1062 | } else { |
05057c06 AN |
1063 | wl1271_error("invalid board type '%s'", board_type_param); |
1064 | wlcore_free_hw(wl); | |
1065 | return -EINVAL; | |
a9c130d5 LC |
1066 | } |
1067 | ||
23ee9bf8 LC |
1068 | wl18xx_conf_init(wl); |
1069 | ||
9a1a6990 LC |
1070 | return wlcore_probe(wl, pdev); |
1071 | } | |
1072 | ||
1073 | static const struct platform_device_id wl18xx_id_table[] __devinitconst = { | |
1074 | { "wl18xx", 0 }, | |
1075 | { } /* Terminating Entry */ | |
1076 | }; | |
1077 | MODULE_DEVICE_TABLE(platform, wl18xx_id_table); | |
1078 | ||
1079 | static struct platform_driver wl18xx_driver = { | |
1080 | .probe = wl18xx_probe, | |
1081 | .remove = __devexit_p(wlcore_remove), | |
1082 | .id_table = wl18xx_id_table, | |
1083 | .driver = { | |
1084 | .name = "wl18xx_driver", | |
1085 | .owner = THIS_MODULE, | |
1086 | } | |
1087 | }; | |
1088 | ||
1089 | static int __init wl18xx_init(void) | |
1090 | { | |
1091 | return platform_driver_register(&wl18xx_driver); | |
1092 | } | |
1093 | module_init(wl18xx_init); | |
1094 | ||
1095 | static void __exit wl18xx_exit(void) | |
1096 | { | |
1097 | platform_driver_unregister(&wl18xx_driver); | |
1098 | } | |
1099 | module_exit(wl18xx_exit); | |
1100 | ||
3a8ddb61 AN |
1101 | module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR); |
1102 | MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or mimo"); | |
1103 | ||
a9c130d5 | 1104 | module_param_named(board_type, board_type_param, charp, S_IRUSR); |
05057c06 AN |
1105 | MODULE_PARM_DESC(board_type, "Board type: fpga, hdk, evb, com8 or " |
1106 | "dvp (default)"); | |
a9c130d5 | 1107 | |
9a1a6990 LC |
1108 | MODULE_LICENSE("GPL v2"); |
1109 | MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); | |
0cd6543f | 1110 | MODULE_FIRMWARE(WL18XX_FW_NAME); |