blob: 85d1600ee340c20056b30ad6de91d2b799695375 [file] [log] [blame]
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02001/*
2 * This file is part of wl1271
3 *
4 * Copyright (C) 2008-2010 Nokia Corporation
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
Luciano Coelhoffeb5012011-11-21 18:55:51 +020025#include <linux/err.h>
26
Luciano Coelhodd5512e2012-04-11 11:03:14 +030027#include <linux/wl12xx.h>
28
Luciano Coelhob2ba99f2011-11-20 23:32:10 +020029#include "../wlcore/wlcore.h"
Luciano Coelhoffeb5012011-11-21 18:55:51 +020030#include "../wlcore/debug.h"
Luciano Coelho4ded91c2012-04-11 10:54:52 +030031#include "../wlcore/io.h"
Luciano Coelhodd5512e2012-04-11 11:03:14 +030032#include "../wlcore/acx.h"
Arik Nemtsovb3b4b4b2011-12-12 11:41:44 +020033#include "../wlcore/tx.h"
Arik Nemtsovcd70f6a2011-12-12 12:11:43 +020034#include "../wlcore/rx.h"
Luciano Coelhob14684a2011-12-12 12:15:08 +020035#include "../wlcore/io.h"
Luciano Coelhodd5512e2012-04-11 11:03:14 +030036#include "../wlcore/boot.h"
Luciano Coelhoffeb5012011-11-21 18:55:51 +020037
Luciano Coelho166b2132011-12-05 16:51:10 +020038#include "wl12xx.h"
Luciano Coelho00782132011-11-29 13:38:37 +020039#include "reg.h"
Luciano Coelho9d68d1e2011-12-02 00:47:45 +020040#include "cmd.h"
41#include "acx.h"
Luciano Coelho10b1e8a2012-05-10 12:14:08 +030042#include "debugfs.h"
Luciano Coelho25a43d72011-11-21 20:37:14 +020043
Luciano Coelhoa5d751b2012-05-10 12:13:43 +030044static char *fref_param;
45static char *tcxo_param;
46
Luciano Coelhoe87288f2011-12-05 16:12:54 +020047static struct wlcore_conf wl12xx_conf = {
48 .sg = {
49 .params = {
50 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
51 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
52 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
53 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
54 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
55 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
56 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
57 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
58 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
59 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
60 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
61 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
62 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
63 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
64 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
65 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
66 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
67 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
68 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
69 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
70 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
71 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
72 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
73 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
74 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
75 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
76 /* active scan params */
77 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
78 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
79 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
80 /* passive scan params */
81 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
82 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
83 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
84 /* passive scan in dual antenna params */
85 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
86 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
87 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
88 /* general params */
89 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
90 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
91 [CONF_SG_BEACON_MISS_PERCENT] = 60,
92 [CONF_SG_DHCP_TIME] = 5000,
93 [CONF_SG_RXT] = 1200,
94 [CONF_SG_TXT] = 1000,
95 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
96 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
97 [CONF_SG_HV3_MAX_SERVED] = 6,
98 [CONF_SG_PS_POLL_TIMEOUT] = 10,
99 [CONF_SG_UPSD_TIMEOUT] = 10,
100 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
101 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
102 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
103 /* AP params */
104 [CONF_AP_BEACON_MISS_TX] = 3,
105 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
106 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
107 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
108 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
109 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
110 /* CTS Diluting params */
111 [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
112 [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
113 },
114 .state = CONF_SG_PROTECTIVE,
115 },
116 .rx = {
117 .rx_msdu_life_time = 512000,
118 .packet_detection_threshold = 0,
119 .ps_poll_timeout = 15,
120 .upsd_timeout = 15,
121 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
122 .rx_cca_threshold = 0,
123 .irq_blk_threshold = 0xFFFF,
124 .irq_pkt_threshold = 0,
125 .irq_timeout = 600,
126 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
127 },
128 .tx = {
129 .tx_energy_detection = 0,
130 .sta_rc_conf = {
131 .enabled_rates = 0,
132 .short_retry_limit = 10,
133 .long_retry_limit = 10,
134 .aflags = 0,
135 },
136 .ac_conf_count = 4,
137 .ac_conf = {
138 [CONF_TX_AC_BE] = {
139 .ac = CONF_TX_AC_BE,
140 .cw_min = 15,
141 .cw_max = 63,
142 .aifsn = 3,
143 .tx_op_limit = 0,
144 },
145 [CONF_TX_AC_BK] = {
146 .ac = CONF_TX_AC_BK,
147 .cw_min = 15,
148 .cw_max = 63,
149 .aifsn = 7,
150 .tx_op_limit = 0,
151 },
152 [CONF_TX_AC_VI] = {
153 .ac = CONF_TX_AC_VI,
154 .cw_min = 15,
155 .cw_max = 63,
156 .aifsn = CONF_TX_AIFS_PIFS,
157 .tx_op_limit = 3008,
158 },
159 [CONF_TX_AC_VO] = {
160 .ac = CONF_TX_AC_VO,
161 .cw_min = 15,
162 .cw_max = 63,
163 .aifsn = CONF_TX_AIFS_PIFS,
164 .tx_op_limit = 1504,
165 },
166 },
167 .max_tx_retries = 100,
168 .ap_aging_period = 300,
169 .tid_conf_count = 4,
170 .tid_conf = {
171 [CONF_TX_AC_BE] = {
172 .queue_id = CONF_TX_AC_BE,
173 .channel_type = CONF_CHANNEL_TYPE_EDCF,
174 .tsid = CONF_TX_AC_BE,
175 .ps_scheme = CONF_PS_SCHEME_LEGACY,
176 .ack_policy = CONF_ACK_POLICY_LEGACY,
177 .apsd_conf = {0, 0},
178 },
179 [CONF_TX_AC_BK] = {
180 .queue_id = CONF_TX_AC_BK,
181 .channel_type = CONF_CHANNEL_TYPE_EDCF,
182 .tsid = CONF_TX_AC_BK,
183 .ps_scheme = CONF_PS_SCHEME_LEGACY,
184 .ack_policy = CONF_ACK_POLICY_LEGACY,
185 .apsd_conf = {0, 0},
186 },
187 [CONF_TX_AC_VI] = {
188 .queue_id = CONF_TX_AC_VI,
189 .channel_type = CONF_CHANNEL_TYPE_EDCF,
190 .tsid = CONF_TX_AC_VI,
191 .ps_scheme = CONF_PS_SCHEME_LEGACY,
192 .ack_policy = CONF_ACK_POLICY_LEGACY,
193 .apsd_conf = {0, 0},
194 },
195 [CONF_TX_AC_VO] = {
196 .queue_id = CONF_TX_AC_VO,
197 .channel_type = CONF_CHANNEL_TYPE_EDCF,
198 .tsid = CONF_TX_AC_VO,
199 .ps_scheme = CONF_PS_SCHEME_LEGACY,
200 .ack_policy = CONF_ACK_POLICY_LEGACY,
201 .apsd_conf = {0, 0},
202 },
203 },
204 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
205 .tx_compl_timeout = 700,
206 .tx_compl_threshold = 4,
207 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
208 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
209 .tmpl_short_retry_limit = 10,
210 .tmpl_long_retry_limit = 10,
211 .tx_watchdog_timeout = 5000,
212 },
213 .conn = {
214 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
215 .listen_interval = 1,
216 .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
217 .suspend_listen_interval = 3,
218 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Eliad Peller186b5a72012-05-15 16:35:20 +0300219 .bcn_filt_ie_count = 3,
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200220 .bcn_filt_ie = {
221 [0] = {
222 .ie = WLAN_EID_CHANNEL_SWITCH,
223 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
224 },
225 [1] = {
226 .ie = WLAN_EID_HT_OPERATION,
227 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
228 },
Eliad Peller186b5a72012-05-15 16:35:20 +0300229 [2] = {
230 .ie = WLAN_EID_ERP_INFO,
231 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
232 },
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200233 },
Igal Chernobelsky7b052212012-05-15 17:08:57 +0300234 .synch_fail_thold = 12,
235 .bss_lose_timeout = 400,
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200236 .beacon_rx_timeout = 10000,
237 .broadcast_timeout = 20000,
238 .rx_broadcast_in_ps = 1,
239 .ps_poll_threshold = 10,
240 .bet_enable = CONF_BET_MODE_ENABLE,
241 .bet_max_consecutive = 50,
242 .psm_entry_retries = 8,
243 .psm_exit_retries = 16,
244 .psm_entry_nullfunc_retries = 3,
Arik Nemtsov6e066922012-05-15 17:08:53 +0300245 .dynamic_ps_timeout = 200,
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200246 .forced_ps = false,
247 .keep_alive_interval = 55000,
248 .max_listen_interval = 20,
249 },
250 .itrim = {
251 .enable = false,
252 .timeout = 50000,
253 },
254 .pm_config = {
255 .host_clk_settling_time = 5000,
Luciano Coelho648f6ed2012-06-07 23:39:24 +0300256 .host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200257 },
258 .roam_trigger = {
259 .trigger_pacing = 1,
260 .avg_weight_rssi_beacon = 20,
261 .avg_weight_rssi_data = 10,
262 .avg_weight_snr_beacon = 20,
263 .avg_weight_snr_data = 10,
264 },
265 .scan = {
266 .min_dwell_time_active = 7500,
267 .max_dwell_time_active = 30000,
268 .min_dwell_time_passive = 100000,
269 .max_dwell_time_passive = 100000,
270 .num_probe_reqs = 2,
271 .split_scan_timeout = 50000,
272 },
273 .sched_scan = {
274 /*
275 * Values are in TU/1000 but since sched scan FW command
276 * params are in TUs rounding up may occur.
277 */
278 .base_dwell_time = 7500,
279 .max_dwell_time_delta = 22500,
280 /* based on 250bits per probe @1Mbps */
281 .dwell_time_delta_per_probe = 2000,
282 /* based on 250bits per probe @6Mbps (plus a bit more) */
283 .dwell_time_delta_per_probe_5 = 350,
284 .dwell_time_passive = 100000,
285 .dwell_time_dfs = 150000,
286 .num_probe_reqs = 2,
287 .rssi_threshold = -90,
288 .snr_threshold = 0,
289 },
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200290 .ht = {
291 .rx_ba_win_size = 8,
292 .tx_ba_win_size = 64,
293 .inactivity_timeout = 10000,
294 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
295 },
Luciano Coelho5453dc12011-12-05 19:52:22 +0200296 /*
297 * Memory config for wl127x chips is given in the
298 * wl12xx_default_priv_conf struct. The below configuration is
299 * for wl128x chips.
300 */
301 .mem = {
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200302 .num_stations = 1,
303 .ssid_profiles = 1,
304 .rx_block_num = 40,
305 .tx_min_block_num = 40,
306 .dynamic_memory = 1,
307 .min_req_tx_blocks = 45,
308 .min_req_rx_blocks = 22,
309 .tx_min = 27,
310 },
311 .fm_coex = {
312 .enable = true,
313 .swallow_period = 5,
314 .n_divider_fref_set_1 = 0xff, /* default */
315 .n_divider_fref_set_2 = 12,
Victor Goldenshtein836d3f22012-05-10 17:08:33 +0300316 .m_divider_fref_set_1 = 0xffff,
317 .m_divider_fref_set_2 = 148, /* default */
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200318 .coex_pll_stabilization_time = 0xffffffff, /* default */
319 .ldo_stabilization_time = 0xffff, /* default */
320 .fm_disturbed_band_margin = 0xff, /* default */
321 .swallow_clk_diff = 0xff, /* default */
322 },
323 .rx_streaming = {
324 .duration = 150,
325 .queues = 0x1,
326 .interval = 20,
327 .always = 0,
328 },
329 .fwlog = {
330 .mode = WL12XX_FWLOG_ON_DEMAND,
331 .mem_blocks = 2,
332 .severity = 0,
333 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
334 .output = WL12XX_FWLOG_OUTPUT_HOST,
335 .threshold = 0,
336 },
337 .rate = {
338 .rate_retry_score = 32000,
339 .per_add = 8192,
340 .per_th1 = 2048,
341 .per_th2 = 4096,
342 .max_per = 8100,
343 .inverse_curiosity_factor = 5,
344 .tx_fail_low_th = 4,
345 .tx_fail_high_th = 10,
346 .per_alpha_shift = 4,
347 .per_add_shift = 13,
348 .per_beta1_shift = 10,
349 .per_beta2_shift = 8,
350 .rate_check_up = 2,
351 .rate_check_down = 12,
352 .rate_retry_policy = {
353 0x00, 0x00, 0x00, 0x00, 0x00,
354 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x00, 0x00, 0x00,
356 },
357 },
358 .hangover = {
359 .recover_time = 0,
360 .hangover_period = 20,
361 .dynamic_mode = 1,
362 .early_termination_mode = 1,
363 .max_period = 20,
364 .min_period = 1,
365 .increase_delta = 1,
366 .decrease_delta = 2,
367 .quiet_time = 4,
368 .increase_time = 1,
369 .window_size = 16,
370 },
371};
372
Luciano Coelho5453dc12011-12-05 19:52:22 +0200373static struct wl12xx_priv_conf wl12xx_default_priv_conf = {
374 .rf = {
375 .tx_per_channel_power_compensation_2 = {
376 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 },
378 .tx_per_channel_power_compensation_5 = {
379 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 },
383 },
384 .mem_wl127x = {
385 .num_stations = 1,
386 .ssid_profiles = 1,
387 .rx_block_num = 70,
388 .tx_min_block_num = 40,
389 .dynamic_memory = 1,
390 .min_req_tx_blocks = 100,
391 .min_req_rx_blocks = 22,
392 .tx_min = 27,
393 },
394
395};
Luciano Coelhoe87288f2011-12-05 16:12:54 +0200396
Arik Nemtsov3edab302011-12-07 23:38:47 +0200397#define WL12XX_TX_HW_BLOCK_SPARE_DEFAULT 1
398#define WL12XX_TX_HW_BLOCK_GEM_SPARE 2
Arik Nemtsovb3b4b4b2011-12-12 11:41:44 +0200399#define WL12XX_TX_HW_BLOCK_SIZE 252
Arik Nemtsov3edab302011-12-07 23:38:47 +0200400
Arik Nemtsov43a8bc52011-12-08 00:43:48 +0200401static const u8 wl12xx_rate_to_idx_2ghz[] = {
402 /* MCS rates are used only with 11n */
403 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */
404 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */
405 6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */
406 5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */
407 4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */
408 3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */
409 2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */
410 1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */
411 0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */
412
413 11, /* WL12XX_CONF_HW_RXTX_RATE_54 */
414 10, /* WL12XX_CONF_HW_RXTX_RATE_48 */
415 9, /* WL12XX_CONF_HW_RXTX_RATE_36 */
416 8, /* WL12XX_CONF_HW_RXTX_RATE_24 */
417
418 /* TI-specific rate */
419 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */
420
421 7, /* WL12XX_CONF_HW_RXTX_RATE_18 */
422 6, /* WL12XX_CONF_HW_RXTX_RATE_12 */
423 3, /* WL12XX_CONF_HW_RXTX_RATE_11 */
424 5, /* WL12XX_CONF_HW_RXTX_RATE_9 */
425 4, /* WL12XX_CONF_HW_RXTX_RATE_6 */
426 2, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */
427 1, /* WL12XX_CONF_HW_RXTX_RATE_2 */
428 0 /* WL12XX_CONF_HW_RXTX_RATE_1 */
429};
430
431static const u8 wl12xx_rate_to_idx_5ghz[] = {
432 /* MCS rates are used only with 11n */
433 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */
434 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */
435 6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */
436 5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */
437 4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */
438 3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */
439 2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */
440 1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */
441 0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */
442
443 7, /* WL12XX_CONF_HW_RXTX_RATE_54 */
444 6, /* WL12XX_CONF_HW_RXTX_RATE_48 */
445 5, /* WL12XX_CONF_HW_RXTX_RATE_36 */
446 4, /* WL12XX_CONF_HW_RXTX_RATE_24 */
447
448 /* TI-specific rate */
449 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */
450
451 3, /* WL12XX_CONF_HW_RXTX_RATE_18 */
452 2, /* WL12XX_CONF_HW_RXTX_RATE_12 */
453 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_11 */
454 1, /* WL12XX_CONF_HW_RXTX_RATE_9 */
455 0, /* WL12XX_CONF_HW_RXTX_RATE_6 */
456 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */
457 CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_2 */
458 CONF_HW_RXTX_RATE_UNSUPPORTED /* WL12XX_CONF_HW_RXTX_RATE_1 */
459};
460
461static const u8 *wl12xx_band_rate_to_idx[] = {
462 [IEEE80211_BAND_2GHZ] = wl12xx_rate_to_idx_2ghz,
463 [IEEE80211_BAND_5GHZ] = wl12xx_rate_to_idx_5ghz
464};
465
466enum wl12xx_hw_rates {
467 WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI = 0,
468 WL12XX_CONF_HW_RXTX_RATE_MCS7,
469 WL12XX_CONF_HW_RXTX_RATE_MCS6,
470 WL12XX_CONF_HW_RXTX_RATE_MCS5,
471 WL12XX_CONF_HW_RXTX_RATE_MCS4,
472 WL12XX_CONF_HW_RXTX_RATE_MCS3,
473 WL12XX_CONF_HW_RXTX_RATE_MCS2,
474 WL12XX_CONF_HW_RXTX_RATE_MCS1,
475 WL12XX_CONF_HW_RXTX_RATE_MCS0,
476 WL12XX_CONF_HW_RXTX_RATE_54,
477 WL12XX_CONF_HW_RXTX_RATE_48,
478 WL12XX_CONF_HW_RXTX_RATE_36,
479 WL12XX_CONF_HW_RXTX_RATE_24,
480 WL12XX_CONF_HW_RXTX_RATE_22,
481 WL12XX_CONF_HW_RXTX_RATE_18,
482 WL12XX_CONF_HW_RXTX_RATE_12,
483 WL12XX_CONF_HW_RXTX_RATE_11,
484 WL12XX_CONF_HW_RXTX_RATE_9,
485 WL12XX_CONF_HW_RXTX_RATE_6,
486 WL12XX_CONF_HW_RXTX_RATE_5_5,
487 WL12XX_CONF_HW_RXTX_RATE_2,
488 WL12XX_CONF_HW_RXTX_RATE_1,
489 WL12XX_CONF_HW_RXTX_RATE_MAX,
490};
Arik Nemtsov3edab302011-12-07 23:38:47 +0200491
Luciano Coelho25a43d72011-11-21 20:37:14 +0200492static struct wlcore_partition_set wl12xx_ptable[PART_TABLE_LEN] = {
493 [PART_DOWN] = {
494 .mem = {
495 .start = 0x00000000,
496 .size = 0x000177c0
497 },
498 .reg = {
499 .start = REGISTERS_BASE,
500 .size = 0x00008800
501 },
502 .mem2 = {
503 .start = 0x00000000,
504 .size = 0x00000000
505 },
506 .mem3 = {
507 .start = 0x00000000,
508 .size = 0x00000000
509 },
510 },
511
Luciano Coelho00782132011-11-29 13:38:37 +0200512 [PART_BOOT] = { /* in wl12xx we can use a mix of work and down
513 * partition here */
514 .mem = {
515 .start = 0x00040000,
516 .size = 0x00014fc0
517 },
518 .reg = {
519 .start = REGISTERS_BASE,
520 .size = 0x00008800
521 },
522 .mem2 = {
523 .start = 0x00000000,
524 .size = 0x00000000
525 },
526 .mem3 = {
527 .start = 0x00000000,
528 .size = 0x00000000
529 },
530 },
531
Luciano Coelho25a43d72011-11-21 20:37:14 +0200532 [PART_WORK] = {
533 .mem = {
534 .start = 0x00040000,
535 .size = 0x00014fc0
536 },
537 .reg = {
538 .start = REGISTERS_BASE,
539 .size = 0x0000a000
540 },
541 .mem2 = {
542 .start = 0x003004f8,
543 .size = 0x00000004
544 },
545 .mem3 = {
546 .start = 0x00040404,
547 .size = 0x00000000
548 },
549 },
550
551 [PART_DRPW] = {
552 .mem = {
553 .start = 0x00040000,
554 .size = 0x00014fc0
555 },
556 .reg = {
557 .start = DRPW_BASE,
558 .size = 0x00006000
559 },
560 .mem2 = {
561 .start = 0x00000000,
562 .size = 0x00000000
563 },
564 .mem3 = {
565 .start = 0x00000000,
566 .size = 0x00000000
567 }
568 }
569};
570
Luciano Coelho00782132011-11-29 13:38:37 +0200571static const int wl12xx_rtable[REG_TABLE_LEN] = {
572 [REG_ECPU_CONTROL] = WL12XX_REG_ECPU_CONTROL,
573 [REG_INTERRUPT_NO_CLEAR] = WL12XX_REG_INTERRUPT_NO_CLEAR,
574 [REG_INTERRUPT_ACK] = WL12XX_REG_INTERRUPT_ACK,
575 [REG_COMMAND_MAILBOX_PTR] = WL12XX_REG_COMMAND_MAILBOX_PTR,
576 [REG_EVENT_MAILBOX_PTR] = WL12XX_REG_EVENT_MAILBOX_PTR,
577 [REG_INTERRUPT_TRIG] = WL12XX_REG_INTERRUPT_TRIG,
578 [REG_INTERRUPT_MASK] = WL12XX_REG_INTERRUPT_MASK,
579 [REG_PC_ON_RECOVERY] = WL12XX_SCR_PAD4,
580 [REG_CHIP_ID_B] = WL12XX_CHIP_ID_B,
581 [REG_CMD_MBOX_ADDRESS] = WL12XX_CMD_MBOX_ADDRESS,
582
583 /* data access memory addresses, used with partition translation */
584 [REG_SLV_MEM_DATA] = WL1271_SLV_MEM_DATA,
585 [REG_SLV_REG_DATA] = WL1271_SLV_REG_DATA,
586
587 /* raw data access memory addresses */
588 [REG_RAW_FW_STATUS_ADDR] = FW_STATUS_ADDR,
589};
590
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200591/* TODO: maybe move to a new header file? */
592#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
593#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
594#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
595
596#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
597#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
598#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
599
Luciano Coelhob14684a2011-12-12 12:15:08 +0200600static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
601{
602 if (wl->chip.id != CHIP_ID_1283_PG20) {
603 struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
Luciano Coelho4b4887e2012-05-10 12:13:45 +0300604 struct wl127x_rx_mem_pool_addr rx_mem_addr;
Luciano Coelhob14684a2011-12-12 12:15:08 +0200605
606 /*
607 * Choose the block we want to read
608 * For aggregated packets, only the first memory block
609 * should be retrieved. The FW takes care of the rest.
610 */
611 u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK;
612
613 rx_mem_addr.addr = (mem_block << 8) +
614 le32_to_cpu(wl_mem_map->packet_memory_pool_start);
615
616 rx_mem_addr.addr_extra = rx_mem_addr.addr + 4;
617
618 wl1271_write(wl, WL1271_SLV_REG_DATA,
619 &rx_mem_addr, sizeof(rx_mem_addr), false);
620 }
621}
622
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200623static int wl12xx_identify_chip(struct wl1271 *wl)
624{
625 int ret = 0;
626
627 switch (wl->chip.id) {
628 case CHIP_ID_1271_PG10:
629 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
630 wl->chip.id);
631
Arik Nemtsov2c0133a2012-05-18 07:46:36 +0300632 wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
633 WLCORE_QUIRK_TKIP_HEADER_SPACE;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200634 wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
635 wl->mr_fw_name = WL127X_FW_NAME_MULTI;
Luciano Coelho5453dc12011-12-05 19:52:22 +0200636 memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
637 sizeof(wl->conf.mem));
Luciano Coelhob14684a2011-12-12 12:15:08 +0200638
639 /* read data preparation is only needed by wl127x */
640 wl->ops->prepare_read = wl127x_prepare_read;
641
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200642 break;
643
644 case CHIP_ID_1271_PG20:
645 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
646 wl->chip.id);
647
Arik Nemtsov2c0133a2012-05-18 07:46:36 +0300648 wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
649 WLCORE_QUIRK_TKIP_HEADER_SPACE;
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200650 wl->plt_fw_name = WL127X_PLT_FW_NAME;
651 wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
652 wl->mr_fw_name = WL127X_FW_NAME_MULTI;
Luciano Coelho5453dc12011-12-05 19:52:22 +0200653 memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
654 sizeof(wl->conf.mem));
Luciano Coelhob14684a2011-12-12 12:15:08 +0200655
656 /* read data preparation is only needed by wl127x */
657 wl->ops->prepare_read = wl127x_prepare_read;
658
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200659 break;
660
661 case CHIP_ID_1283_PG20:
662 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
663 wl->chip.id);
664 wl->plt_fw_name = WL128X_PLT_FW_NAME;
665 wl->sr_fw_name = WL128X_FW_NAME_SINGLE;
666 wl->mr_fw_name = WL128X_FW_NAME_MULTI;
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +0300667
668 /* wl128x requires TX blocksize alignment */
Arik Nemtsov2c0133a2012-05-18 07:46:36 +0300669 wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
670 WLCORE_QUIRK_TKIP_HEADER_SPACE;
Luciano Coelhob5d6d9b2012-06-05 00:02:25 +0300671
Luciano Coelho6f7dd162011-11-29 16:27:31 +0200672 break;
673 case CHIP_ID_1283_PG10:
674 default:
675 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
676 ret = -ENODEV;
677 goto out;
678 }
679
680out:
681 return ret;
682}
683
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300684static void wl12xx_top_reg_write(struct wl1271 *wl, int addr, u16 val)
685{
686 /* write address >> 1 + 0x30000 to OCP_POR_CTR */
687 addr = (addr >> 1) + 0x30000;
688 wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr);
689
690 /* write value to OCP_POR_WDATA */
691 wl1271_write32(wl, WL12XX_OCP_DATA_WRITE, val);
692
693 /* write 1 to OCP_CMD */
694 wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE);
695}
696
697static u16 wl12xx_top_reg_read(struct wl1271 *wl, int addr)
698{
699 u32 val;
700 int timeout = OCP_CMD_LOOP;
701
702 /* write address >> 1 + 0x30000 to OCP_POR_CTR */
703 addr = (addr >> 1) + 0x30000;
704 wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr);
705
706 /* write 2 to OCP_CMD */
707 wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ);
708
709 /* poll for data ready */
710 do {
711 val = wl1271_read32(wl, WL12XX_OCP_DATA_READ);
712 } while (!(val & OCP_READY_MASK) && --timeout);
713
714 if (!timeout) {
715 wl1271_warning("Top register access timed out.");
716 return 0xffff;
717 }
718
719 /* check data status and return if OK */
720 if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK)
721 return val & 0xffff;
722 else {
723 wl1271_warning("Top register access returned error.");
724 return 0xffff;
725 }
726}
727
728static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
729{
730 u16 spare_reg;
731
732 /* Mask bits [2] & [8:4] in the sys_clk_cfg register */
733 spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
734 if (spare_reg == 0xFFFF)
735 return -EFAULT;
736 spare_reg |= (BIT(3) | BIT(5) | BIT(6));
737 wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
738
739 /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */
740 wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG,
741 WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
742
743 /* Delay execution for 15msec, to let the HW settle */
744 mdelay(15);
745
746 return 0;
747}
748
749static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
750{
751 u16 tcxo_detection;
752
753 tcxo_detection = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG);
754 if (tcxo_detection & TCXO_DET_FAILED)
755 return false;
756
757 return true;
758}
759
760static bool wl128x_is_fref_valid(struct wl1271 *wl)
761{
762 u16 fref_detection;
763
764 fref_detection = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG);
765 if (fref_detection & FREF_CLK_DETECT_FAIL)
766 return false;
767
768 return true;
769}
770
771static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl)
772{
773 wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
774 wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
775 wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL);
776
777 return 0;
778}
779
780static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
781{
782 u16 spare_reg;
783 u16 pll_config;
784 u8 input_freq;
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300785 struct wl12xx_priv *priv = wl->priv;
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300786
787 /* Mask bits [3:1] in the sys_clk_cfg register */
788 spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG);
789 if (spare_reg == 0xFFFF)
790 return -EFAULT;
791 spare_reg |= BIT(2);
792 wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
793
794 /* Handle special cases of the TCXO clock */
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300795 if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
796 priv->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300797 return wl128x_manually_configure_mcs_pll(wl);
798
799 /* Set the input frequency according to the selected clock source */
800 input_freq = (clk & 1) + 1;
801
802 pll_config = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG);
803 if (pll_config == 0xFFFF)
804 return -EFAULT;
805 pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT);
806 pll_config |= MCS_PLL_ENABLE_HP;
807 wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config);
808
809 return 0;
810}
811
812/*
813 * WL128x has two clocks input - TCXO and FREF.
814 * TCXO is the main clock of the device, while FREF is used to sync
815 * between the GPS and the cellular modem.
816 * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used
817 * as the WLAN/BT main clock.
818 */
819static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
820{
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300821 struct wl12xx_priv *priv = wl->priv;
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300822 u16 sys_clk_cfg;
823
824 /* For XTAL-only modes, FREF will be used after switching from TCXO */
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300825 if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
826 priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300827 if (!wl128x_switch_tcxo_to_fref(wl))
828 return -EINVAL;
829 goto fref_clk;
830 }
831
832 /* Query the HW, to determine which clock source we should use */
833 sys_clk_cfg = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG);
834 if (sys_clk_cfg == 0xFFFF)
835 return -EINVAL;
836 if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF)
837 goto fref_clk;
838
839 /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300840 if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
841 priv->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300842 if (!wl128x_switch_tcxo_to_fref(wl))
843 return -EINVAL;
844 goto fref_clk;
845 }
846
847 /* TCXO clock is selected */
848 if (!wl128x_is_tcxo_valid(wl))
849 return -EINVAL;
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300850 *selected_clock = priv->tcxo_clock;
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300851 goto config_mcs_pll;
852
853fref_clk:
854 /* FREF clock is selected */
855 if (!wl128x_is_fref_valid(wl))
856 return -EINVAL;
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300857 *selected_clock = priv->ref_clock;
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300858
859config_mcs_pll:
860 return wl128x_configure_mcs_pll(wl, *selected_clock);
861}
862
863static int wl127x_boot_clk(struct wl1271 *wl)
864{
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300865 struct wl12xx_priv *priv = wl->priv;
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300866 u32 pause;
867 u32 clk;
868
869 if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
870 wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION;
871
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300872 if (priv->ref_clock == CONF_REF_CLK_19_2_E ||
873 priv->ref_clock == CONF_REF_CLK_38_4_E ||
874 priv->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300875 /* ref clk: 19.2/38.4/38.4-XTAL */
876 clk = 0x3;
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300877 else if (priv->ref_clock == CONF_REF_CLK_26_E ||
Grant Ericksone16de2c2012-06-01 09:19:01 -0700878 priv->ref_clock == CONF_REF_CLK_26_M_XTAL ||
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300879 priv->ref_clock == CONF_REF_CLK_52_E)
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300880 /* ref clk: 26/52 */
881 clk = 0x5;
882 else
883 return -EINVAL;
884
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300885 if (priv->ref_clock != CONF_REF_CLK_19_2_E) {
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300886 u16 val;
887 /* Set clock type (open drain) */
888 val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE);
889 val &= FREF_CLK_TYPE_BITS;
890 wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
891
892 /* Set clock pull mode (no pull) */
893 val = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL);
894 val |= NO_PULL;
895 wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val);
896 } else {
897 u16 val;
898 /* Set clock polarity */
899 val = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY);
900 val &= FREF_CLK_POLARITY_BITS;
901 val |= CLK_REQ_OUTN_SEL;
902 wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
903 }
904
905 wl1271_write32(wl, WL12XX_PLL_PARAMETERS, clk);
906
907 pause = wl1271_read32(wl, WL12XX_PLL_PARAMETERS);
908
909 wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
910
911 pause &= ~(WU_COUNTER_PAUSE_VAL);
912 pause |= WU_COUNTER_PAUSE_VAL;
913 wl1271_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause);
914
915 return 0;
916}
917
918static int wl1271_boot_soft_reset(struct wl1271 *wl)
919{
920 unsigned long timeout;
921 u32 boot_data;
922
923 /* perform soft reset */
924 wl1271_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
925
926 /* SOFT_RESET is self clearing */
927 timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
928 while (1) {
929 boot_data = wl1271_read32(wl, WL12XX_SLV_SOFT_RESET);
930 wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
931 if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
932 break;
933
934 if (time_after(jiffies, timeout)) {
935 /* 1.2 check pWhalBus->uSelfClearTime if the
936 * timeout was reached */
937 wl1271_error("soft reset timeout");
938 return -1;
939 }
940
941 udelay(SOFT_RESET_STALL_TIME);
942 }
943
944 /* disable Rx/Tx */
945 wl1271_write32(wl, WL12XX_ENABLE, 0x0);
946
947 /* disable auto calibration on start*/
948 wl1271_write32(wl, WL12XX_SPARE_A2, 0xffff);
949
950 return 0;
951}
952
953static int wl12xx_pre_boot(struct wl1271 *wl)
954{
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300955 struct wl12xx_priv *priv = wl->priv;
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300956 int ret = 0;
957 u32 clk;
958 int selected_clock = -1;
959
960 if (wl->chip.id == CHIP_ID_1283_PG20) {
961 ret = wl128x_boot_clk(wl, &selected_clock);
962 if (ret < 0)
963 goto out;
964 } else {
965 ret = wl127x_boot_clk(wl);
966 if (ret < 0)
967 goto out;
968 }
969
970 /* Continue the ELP wake up sequence */
971 wl1271_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
972 udelay(500);
973
974 wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
975
976 /* Read-modify-write DRPW_SCRATCH_START register (see next state)
977 to be used by DRPw FW. The RTRIM value will be added by the FW
978 before taking DRPw out of reset */
979
980 clk = wl1271_read32(wl, WL12XX_DRPW_SCRATCH_START);
981
982 wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
983
984 if (wl->chip.id == CHIP_ID_1283_PG20)
985 clk |= ((selected_clock & 0x3) << 1) << 4;
986 else
Luciano Coelhoa5d751b2012-05-10 12:13:43 +0300987 clk |= (priv->ref_clock << 1) << 4;
Luciano Coelhodd5512e2012-04-11 11:03:14 +0300988
989 wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
990
991 wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
992
993 /* Disable interrupts */
994 wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
995
996 ret = wl1271_boot_soft_reset(wl);
997 if (ret < 0)
998 goto out;
999
1000out:
1001 return ret;
1002}
1003
1004static void wl12xx_pre_upload(struct wl1271 *wl)
1005{
Yoni Divinsky4a6c7892012-05-08 14:02:12 +03001006 u32 tmp, polarity;
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001007
1008 /* write firmware's last address (ie. it's length) to
1009 * ACX_EEPROMLESS_IND_REG */
1010 wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
1011
1012 wl1271_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND);
1013
1014 tmp = wlcore_read_reg(wl, REG_CHIP_ID_B);
1015
1016 wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
1017
1018 /* 6. read the EEPROM parameters */
1019 tmp = wl1271_read32(wl, WL12XX_SCR_PAD2);
1020
1021 /* WL1271: The reference driver skips steps 7 to 10 (jumps directly
1022 * to upload_fw) */
1023
1024 if (wl->chip.id == CHIP_ID_1283_PG20)
1025 wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001026
Yoni Divinsky4a6c7892012-05-08 14:02:12 +03001027 /* polarity must be set before the firmware is loaded */
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001028 polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY);
1029
1030 /* We use HIGH polarity, so unset the LOW bit */
1031 polarity &= ~POLARITY_LOW;
1032 wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
1033
Yoni Divinsky4a6c7892012-05-08 14:02:12 +03001034}
1035
1036static void wl12xx_enable_interrupts(struct wl1271 *wl)
1037{
Ido Reisf5755fe2012-04-23 17:35:25 +03001038 wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL12XX_ACX_ALL_EVENTS_VECTOR);
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001039
1040 wlcore_enable_interrupts(wl);
1041 wlcore_write_reg(wl, REG_INTERRUPT_MASK,
Ido Reisf5755fe2012-04-23 17:35:25 +03001042 WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001043
1044 wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
1045}
1046
1047static int wl12xx_boot(struct wl1271 *wl)
1048{
1049 int ret;
1050
1051 ret = wl12xx_pre_boot(wl);
1052 if (ret < 0)
1053 goto out;
1054
1055 ret = wlcore_boot_upload_nvs(wl);
1056 if (ret < 0)
1057 goto out;
1058
1059 wl12xx_pre_upload(wl);
1060
1061 ret = wlcore_boot_upload_firmware(wl);
1062 if (ret < 0)
1063 goto out;
1064
1065 ret = wlcore_boot_run_firmware(wl);
1066 if (ret < 0)
1067 goto out;
1068
1069 wl12xx_enable_interrupts(wl);
1070
1071out:
1072 return ret;
1073}
1074
Arik Nemtsov5d10b192011-12-13 12:27:22 +02001075static void wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
1076 void *buf, size_t len)
Luciano Coelhof16ff752012-04-11 10:15:46 +03001077{
Arik Nemtsov5d10b192011-12-13 12:27:22 +02001078 wl1271_write(wl, cmd_box_addr, buf, len, false);
Luciano Coelhof16ff752012-04-11 10:15:46 +03001079 wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD);
1080}
1081
1082static void wl12xx_ack_event(struct wl1271 *wl)
1083{
1084 wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_EVENT_ACK);
1085}
1086
Arik Nemtsovb3b4b4b2011-12-12 11:41:44 +02001087static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
1088{
1089 u32 blk_size = WL12XX_TX_HW_BLOCK_SIZE;
1090 u32 align_len = wlcore_calc_packet_alignment(wl, len);
1091
1092 return (align_len + blk_size - 1) / blk_size + spare_blks;
1093}
1094
Arik Nemtsov4a3b97ee2011-12-12 11:44:27 +02001095static void
1096wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
1097 u32 blks, u32 spare_blks)
1098{
1099 if (wl->chip.id == CHIP_ID_1283_PG20) {
1100 desc->wl128x_mem.total_mem_blocks = blks;
1101 } else {
1102 desc->wl127x_mem.extra_blocks = spare_blks;
1103 desc->wl127x_mem.total_mem_blocks = blks;
1104 }
1105}
1106
Arik Nemtsov6f266e92011-12-12 11:47:09 +02001107static void
1108wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
1109 struct sk_buff *skb)
1110{
1111 u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len);
1112
1113 if (wl->chip.id == CHIP_ID_1283_PG20) {
1114 desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
1115 desc->length = cpu_to_le16(aligned_len >> 2);
1116
1117 wl1271_debug(DEBUG_TX,
1118 "tx_fill_hdr: hlid: %d len: %d life: %d mem: %d extra: %d",
1119 desc->hlid,
1120 le16_to_cpu(desc->length),
1121 le16_to_cpu(desc->life_time),
1122 desc->wl128x_mem.total_mem_blocks,
1123 desc->wl128x_mem.extra_bytes);
1124 } else {
1125 /* calculate number of padding bytes */
1126 int pad = aligned_len - skb->len;
1127 desc->tx_attr |=
1128 cpu_to_le16(pad << TX_HW_ATTR_OFST_LAST_WORD_PAD);
1129
1130 /* Store the aligned length in terms of words */
1131 desc->length = cpu_to_le16(aligned_len >> 2);
1132
1133 wl1271_debug(DEBUG_TX,
1134 "tx_fill_hdr: pad: %d hlid: %d len: %d life: %d mem: %d",
1135 pad, desc->hlid,
1136 le16_to_cpu(desc->length),
1137 le16_to_cpu(desc->life_time),
1138 desc->wl127x_mem.total_mem_blocks);
1139 }
1140}
1141
Arik Nemtsovcd70f6a2011-12-12 12:11:43 +02001142static enum wl_rx_buf_align
1143wl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
1144{
1145 if (rx_desc & RX_BUF_UNALIGNED_PAYLOAD)
1146 return WLCORE_RX_BUF_UNALIGNED;
1147
1148 return WLCORE_RX_BUF_ALIGNED;
1149}
1150
Arik Nemtsov41581492011-12-12 12:18:17 +02001151static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
1152 u32 data_len)
1153{
1154 struct wl1271_rx_descriptor *desc = rx_data;
1155
1156 /* invalid packet */
1157 if (data_len < sizeof(*desc) ||
1158 data_len < sizeof(*desc) + desc->pad_len)
1159 return 0;
1160
1161 return data_len - sizeof(*desc) - desc->pad_len;
1162}
1163
Arik Nemtsov53d67a52011-12-12 11:32:37 +02001164static void wl12xx_tx_delayed_compl(struct wl1271 *wl)
1165{
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03001166 if (wl->fw_status_1->tx_results_counter ==
1167 (wl->tx_results_count & 0xff))
Arik Nemtsov53d67a52011-12-12 11:32:37 +02001168 return;
1169
1170 wl1271_tx_complete(wl);
1171}
1172
Luciano Coelho9d68d1e2011-12-02 00:47:45 +02001173static int wl12xx_hw_init(struct wl1271 *wl)
1174{
1175 int ret;
1176
1177 if (wl->chip.id == CHIP_ID_1283_PG20) {
1178 u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
1179
1180 ret = wl128x_cmd_general_parms(wl);
1181 if (ret < 0)
1182 goto out;
1183 ret = wl128x_cmd_radio_parms(wl);
1184 if (ret < 0)
1185 goto out;
1186
1187 if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
1188 /* Enable SDIO padding */
1189 host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
1190
1191 /* Must be before wl1271_acx_init_mem_config() */
1192 ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
1193 if (ret < 0)
1194 goto out;
1195 } else {
1196 ret = wl1271_cmd_general_parms(wl);
1197 if (ret < 0)
1198 goto out;
1199 ret = wl1271_cmd_radio_parms(wl);
1200 if (ret < 0)
1201 goto out;
1202 ret = wl1271_cmd_ext_radio_parms(wl);
1203 if (ret < 0)
1204 goto out;
1205 }
1206out:
1207 return ret;
1208}
1209
Arik Nemtsovfa7930a2011-12-13 13:18:17 +02001210static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl,
1211 struct wl12xx_vif *wlvif)
1212{
1213 return wlvif->rate_set;
1214}
1215
Luciano Coelho80cd6612011-12-06 22:24:57 +02001216static int wl12xx_identify_fw(struct wl1271 *wl)
1217{
1218 unsigned int *fw_ver = wl->chip.fw_ver;
1219
1220 /* Only new station firmwares support routing fw logs to the host */
1221 if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1222 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN))
1223 wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED;
1224
1225 /* This feature is not yet supported for AP mode */
1226 if (fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP)
1227 wl->quirks |= WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED;
1228
1229 return 0;
1230}
1231
Luciano Coelhoe87288f2011-12-05 16:12:54 +02001232static void wl12xx_conf_init(struct wl1271 *wl)
1233{
Luciano Coelho5453dc12011-12-05 19:52:22 +02001234 struct wl12xx_priv *priv = wl->priv;
1235
Luciano Coelhoe87288f2011-12-05 16:12:54 +02001236 /* apply driver default configuration */
1237 memcpy(&wl->conf, &wl12xx_conf, sizeof(wl12xx_conf));
Luciano Coelho5453dc12011-12-05 19:52:22 +02001238
1239 /* apply default private configuration */
1240 memcpy(&priv->conf, &wl12xx_default_priv_conf, sizeof(priv->conf));
Luciano Coelhoe87288f2011-12-05 16:12:54 +02001241}
1242
Luciano Coelho30d9b4a2012-04-11 11:07:28 +03001243static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
1244{
1245 bool supported = false;
1246 u8 major, minor;
1247
1248 if (wl->chip.id == CHIP_ID_1283_PG20) {
1249 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
1250 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
1251
1252 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
1253 if (major > 2 || (major == 2 && minor >= 1))
1254 supported = true;
1255 } else {
1256 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
1257 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
1258
1259 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
1260 if (major == 3 && minor >= 1)
1261 supported = true;
1262 }
1263
1264 wl1271_debug(DEBUG_PROBE,
1265 "PG Ver major = %d minor = %d, MAC %s present",
1266 major, minor, supported ? "is" : "is not");
1267
1268 return supported;
1269}
1270
1271static void wl12xx_get_fuse_mac(struct wl1271 *wl)
1272{
1273 u32 mac1, mac2;
1274
1275 wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
1276
1277 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
1278 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
1279
1280 /* these are the two parts of the BD_ADDR */
1281 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
1282 ((mac1 & 0xff000000) >> 24);
1283 wl->fuse_nic_addr = mac1 & 0xffffff;
1284
1285 wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
1286}
1287
Luciano Coelho4ded91c2012-04-11 10:54:52 +03001288static s8 wl12xx_get_pg_ver(struct wl1271 *wl)
1289{
1290 u32 die_info;
1291
1292 if (wl->chip.id == CHIP_ID_1283_PG20)
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001293 die_info = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
Luciano Coelho4ded91c2012-04-11 10:54:52 +03001294 else
Luciano Coelhodd5512e2012-04-11 11:03:14 +03001295 die_info = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
Luciano Coelho4ded91c2012-04-11 10:54:52 +03001296
1297 return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
1298}
1299
Luciano Coelho30d9b4a2012-04-11 11:07:28 +03001300static void wl12xx_get_mac(struct wl1271 *wl)
1301{
1302 if (wl12xx_mac_in_fuse(wl))
1303 wl12xx_get_fuse_mac(wl);
1304}
1305
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001306static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,
1307 struct wl1271_tx_hw_descr *desc,
1308 struct sk_buff *skb)
1309{
1310 desc->wl12xx_reserved = 0;
1311}
1312
Luciano Coelhoc331b342012-05-10 12:13:49 +03001313static int wl12xx_plt_init(struct wl1271 *wl)
1314{
1315 int ret;
1316
1317 ret = wl->ops->boot(wl);
1318 if (ret < 0)
1319 goto out;
1320
1321 ret = wl->ops->hw_init(wl);
1322 if (ret < 0)
1323 goto out_irq_disable;
1324
1325 ret = wl1271_acx_init_mem_config(wl);
1326 if (ret < 0)
1327 goto out_irq_disable;
1328
1329 ret = wl12xx_acx_mem_cfg(wl);
1330 if (ret < 0)
1331 goto out_free_memmap;
1332
1333 /* Enable data path */
1334 ret = wl1271_cmd_data_path(wl, 1);
1335 if (ret < 0)
1336 goto out_free_memmap;
1337
1338 /* Configure for CAM power saving (ie. always active) */
1339 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
1340 if (ret < 0)
1341 goto out_free_memmap;
1342
1343 /* configure PM */
1344 ret = wl1271_acx_pm_config(wl);
1345 if (ret < 0)
1346 goto out_free_memmap;
1347
1348 goto out;
1349
1350out_free_memmap:
1351 kfree(wl->target_mem_map);
1352 wl->target_mem_map = NULL;
1353
1354out_irq_disable:
1355 mutex_unlock(&wl->mutex);
1356 /* Unlocking the mutex in the middle of handling is
1357 inherently unsafe. In this case we deem it safe to do,
1358 because we need to let any possibly pending IRQ out of
1359 the system (and while we are WL1271_STATE_OFF the IRQ
1360 work function will not do anything.) Also, any other
1361 possible concurrent operations will fail due to the
1362 current state, hence the wl1271 struct should be safe. */
1363 wlcore_disable_interrupts(wl);
1364 mutex_lock(&wl->mutex);
1365out:
1366 return ret;
1367}
1368
Arik Nemtsov32bb2c02012-05-18 07:46:37 +03001369static int wl12xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
1370{
1371 if (is_gem)
1372 return WL12XX_TX_HW_BLOCK_GEM_SPARE;
1373
1374 return WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
1375}
1376
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001377static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
1378 struct ieee80211_vif *vif,
1379 struct ieee80211_sta *sta,
1380 struct ieee80211_key_conf *key_conf)
1381{
1382 return wlcore_set_key(wl, cmd, vif, sta, key_conf);
1383}
1384
Luciano Coelho6f7dd162011-11-29 16:27:31 +02001385static struct wlcore_ops wl12xx_ops = {
Arik Nemtsov4a3b97ee2011-12-12 11:44:27 +02001386 .identify_chip = wl12xx_identify_chip,
Luciano Coelho80cd6612011-12-06 22:24:57 +02001387 .identify_fw = wl12xx_identify_fw,
Arik Nemtsov4a3b97ee2011-12-12 11:44:27 +02001388 .boot = wl12xx_boot,
Luciano Coelhoc331b342012-05-10 12:13:49 +03001389 .plt_init = wl12xx_plt_init,
Arik Nemtsov4a3b97ee2011-12-12 11:44:27 +02001390 .trigger_cmd = wl12xx_trigger_cmd,
1391 .ack_event = wl12xx_ack_event,
1392 .calc_tx_blocks = wl12xx_calc_tx_blocks,
1393 .set_tx_desc_blocks = wl12xx_set_tx_desc_blocks,
Arik Nemtsov6f266e92011-12-12 11:47:09 +02001394 .set_tx_desc_data_len = wl12xx_set_tx_desc_data_len,
Arik Nemtsovcd70f6a2011-12-12 12:11:43 +02001395 .get_rx_buf_align = wl12xx_get_rx_buf_align,
Arik Nemtsov41581492011-12-12 12:18:17 +02001396 .get_rx_packet_len = wl12xx_get_rx_packet_len,
Arik Nemtsov53d67a52011-12-12 11:32:37 +02001397 .tx_immediate_compl = NULL,
1398 .tx_delayed_compl = wl12xx_tx_delayed_compl,
Luciano Coelho9d68d1e2011-12-02 00:47:45 +02001399 .hw_init = wl12xx_hw_init,
Arik Nemtsov8a9affc2011-12-13 12:15:09 +02001400 .init_vif = NULL,
Arik Nemtsovfa7930a2011-12-13 13:18:17 +02001401 .sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask,
Arik Nemtsov4a3b97ee2011-12-12 11:44:27 +02001402 .get_pg_ver = wl12xx_get_pg_ver,
1403 .get_mac = wl12xx_get_mac,
Arik Nemtsov2fc28de2012-05-10 12:13:27 +03001404 .set_tx_desc_csum = wl12xx_set_tx_desc_csum,
Arik Nemtsov169da042012-05-10 12:13:28 +03001405 .set_rx_csum = NULL,
Arik Nemtsovebc7e572012-05-10 12:13:34 +03001406 .ap_get_mimo_wide_rate_mask = NULL,
Luciano Coelhoad62d812012-05-10 12:14:19 +03001407 .debugfs_init = wl12xx_debugfs_add_files,
Arik Nemtsov32bb2c02012-05-18 07:46:37 +03001408 .get_spare_blocks = wl12xx_get_spare_blocks,
Arik Nemtsova1c597f2012-05-18 07:46:40 +03001409 .set_key = wl12xx_set_key,
Ido Reis9fccc822012-05-13 14:53:40 +03001410 .pre_pkt_send = NULL,
Luciano Coelho6f7dd162011-11-29 16:27:31 +02001411};
1412
Arik Nemtsov4a589a62011-12-13 13:20:44 +02001413static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
1414 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
1415 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT),
1416 .ht_supported = true,
1417 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
1418 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8,
1419 .mcs = {
1420 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
1421 .rx_highest = cpu_to_le16(72),
1422 .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
1423 },
1424};
1425
Luciano Coelhoffeb5012011-11-21 18:55:51 +02001426static int __devinit wl12xx_probe(struct platform_device *pdev)
1427{
Luciano Coelhoa5d751b2012-05-10 12:13:43 +03001428 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
Luciano Coelhoffeb5012011-11-21 18:55:51 +02001429 struct wl1271 *wl;
1430 struct ieee80211_hw *hw;
Arik Nemtsov96e0c682011-12-07 21:09:03 +02001431 struct wl12xx_priv *priv;
Luciano Coelhoffeb5012011-11-21 18:55:51 +02001432
Arik Nemtsov96e0c682011-12-07 21:09:03 +02001433 hw = wlcore_alloc_hw(sizeof(*priv));
Luciano Coelhoffeb5012011-11-21 18:55:51 +02001434 if (IS_ERR(hw)) {
1435 wl1271_error("can't allocate hw");
1436 return PTR_ERR(hw);
1437 }
1438
1439 wl = hw->priv;
Luciano Coelhoa5d751b2012-05-10 12:13:43 +03001440 priv = wl->priv;
Luciano Coelhoc31be252011-11-21 19:25:24 +02001441 wl->ops = &wl12xx_ops;
Luciano Coelho25a43d72011-11-21 20:37:14 +02001442 wl->ptable = wl12xx_ptable;
Luciano Coelho00782132011-11-29 13:38:37 +02001443 wl->rtable = wl12xx_rtable;
Arik Nemtsov72b06242011-12-07 21:21:51 +02001444 wl->num_tx_desc = 16;
Arik Nemtsov0afd04e2012-05-10 12:13:54 +03001445 wl->num_rx_desc = 8;
Arik Nemtsov43a8bc52011-12-08 00:43:48 +02001446 wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
1447 wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
1448 wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
Arik Nemtsov6bac40a2011-12-12 12:08:25 +02001449 wl->fw_status_priv_len = 0;
Luciano Coelho10b1e8a2012-05-10 12:14:08 +03001450 wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
Eliad Pellerbfb92ca2012-05-15 17:09:00 +03001451 memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], &wl12xx_ht_cap,
1452 sizeof(wl12xx_ht_cap));
1453 memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], &wl12xx_ht_cap,
1454 sizeof(wl12xx_ht_cap));
Luciano Coelhoe87288f2011-12-05 16:12:54 +02001455 wl12xx_conf_init(wl);
Luciano Coelhoffeb5012011-11-21 18:55:51 +02001456
Luciano Coelhoa5d751b2012-05-10 12:13:43 +03001457 if (!fref_param) {
1458 priv->ref_clock = pdata->board_ref_clock;
1459 } else {
1460 if (!strcmp(fref_param, "19.2"))
1461 priv->ref_clock = WL12XX_REFCLOCK_19;
1462 else if (!strcmp(fref_param, "26"))
1463 priv->ref_clock = WL12XX_REFCLOCK_26;
1464 else if (!strcmp(fref_param, "26x"))
1465 priv->ref_clock = WL12XX_REFCLOCK_26_XTAL;
1466 else if (!strcmp(fref_param, "38.4"))
1467 priv->ref_clock = WL12XX_REFCLOCK_38;
1468 else if (!strcmp(fref_param, "38.4x"))
1469 priv->ref_clock = WL12XX_REFCLOCK_38_XTAL;
1470 else if (!strcmp(fref_param, "52"))
1471 priv->ref_clock = WL12XX_REFCLOCK_52;
1472 else
1473 wl1271_error("Invalid fref parameter %s", fref_param);
1474 }
1475
1476 if (!tcxo_param) {
1477 priv->tcxo_clock = pdata->board_tcxo_clock;
1478 } else {
1479 if (!strcmp(tcxo_param, "19.2"))
1480 priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2;
1481 else if (!strcmp(tcxo_param, "26"))
1482 priv->tcxo_clock = WL12XX_TCXOCLOCK_26;
1483 else if (!strcmp(tcxo_param, "38.4"))
1484 priv->tcxo_clock = WL12XX_TCXOCLOCK_38_4;
1485 else if (!strcmp(tcxo_param, "52"))
1486 priv->tcxo_clock = WL12XX_TCXOCLOCK_52;
1487 else if (!strcmp(tcxo_param, "16.368"))
1488 priv->tcxo_clock = WL12XX_TCXOCLOCK_16_368;
1489 else if (!strcmp(tcxo_param, "32.736"))
1490 priv->tcxo_clock = WL12XX_TCXOCLOCK_32_736;
1491 else if (!strcmp(tcxo_param, "16.8"))
1492 priv->tcxo_clock = WL12XX_TCXOCLOCK_16_8;
1493 else if (!strcmp(tcxo_param, "33.6"))
1494 priv->tcxo_clock = WL12XX_TCXOCLOCK_33_6;
1495 else
1496 wl1271_error("Invalid tcxo parameter %s", tcxo_param);
1497 }
1498
Luciano Coelhoffeb5012011-11-21 18:55:51 +02001499 return wlcore_probe(wl, pdev);
1500}
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02001501
1502static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
1503 { "wl12xx", 0 },
1504 { } /* Terminating Entry */
1505};
1506MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
1507
1508static struct platform_driver wl12xx_driver = {
Luciano Coelhoffeb5012011-11-21 18:55:51 +02001509 .probe = wl12xx_probe,
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02001510 .remove = __devexit_p(wlcore_remove),
1511 .id_table = wl12xx_id_table,
1512 .driver = {
1513 .name = "wl12xx_driver",
1514 .owner = THIS_MODULE,
1515 }
1516};
1517
1518static int __init wl12xx_init(void)
1519{
1520 return platform_driver_register(&wl12xx_driver);
1521}
1522module_init(wl12xx_init);
1523
1524static void __exit wl12xx_exit(void)
1525{
1526 platform_driver_unregister(&wl12xx_driver);
1527}
1528module_exit(wl12xx_exit);
1529
Luciano Coelhoa5d751b2012-05-10 12:13:43 +03001530module_param_named(fref, fref_param, charp, 0);
1531MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52");
1532
1533module_param_named(tcxo, tcxo_param, charp, 0);
1534MODULE_PARM_DESC(tcxo,
1535 "TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6");
1536
Luciano Coelhob2ba99f2011-11-20 23:32:10 +02001537MODULE_LICENSE("GPL v2");
1538MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Luciano Coelho6f7dd162011-11-29 16:27:31 +02001539MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
1540MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
1541MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
1542MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
1543MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
1544MODULE_FIRMWARE(WL128X_PLT_FW_NAME);