xref: /openbmc/linux/drivers/net/wireless/ti/wl12xx/main.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b2ba99ffSLuciano Coelho /*
3b2ba99ffSLuciano Coelho  * This file is part of wl1271
4b2ba99ffSLuciano Coelho  *
5b2ba99ffSLuciano Coelho  * Copyright (C) 2008-2010 Nokia Corporation
6b2ba99ffSLuciano Coelho  */
7b2ba99ffSLuciano Coelho 
8b2ba99ffSLuciano Coelho #include <linux/module.h>
9ac316725SRandy Dunlap #include <linux/mod_devicetable.h>
10b2ba99ffSLuciano Coelho #include <linux/platform_device.h>
11b2ba99ffSLuciano Coelho 
12ffeb501cSLuciano Coelho #include <linux/err.h>
13ffeb501cSLuciano Coelho 
14b2ba99ffSLuciano Coelho #include "../wlcore/wlcore.h"
15ffeb501cSLuciano Coelho #include "../wlcore/debug.h"
164ded91ceSLuciano Coelho #include "../wlcore/io.h"
17dd5512ebSLuciano Coelho #include "../wlcore/acx.h"
18b3b4b4b8SArik Nemtsov #include "../wlcore/tx.h"
19cd70f6a4SArik Nemtsov #include "../wlcore/rx.h"
20dd5512ebSLuciano Coelho #include "../wlcore/boot.h"
21ffeb501cSLuciano Coelho 
22166b2136SLuciano Coelho #include "wl12xx.h"
2300782136SLuciano Coelho #include "reg.h"
249d68d1eeSLuciano Coelho #include "cmd.h"
259d68d1eeSLuciano Coelho #include "acx.h"
2678e28062SEliad Peller #include "scan.h"
27c50a2825SEliad Peller #include "event.h"
2810b1e8a2SLuciano Coelho #include "debugfs.h"
29133b7326SGuy Mishol #include "conf.h"
3025a43d78SLuciano Coelho 
31a5d751bbSLuciano Coelho static char *fref_param;
32a5d751bbSLuciano Coelho static char *tcxo_param;
33a5d751bbSLuciano Coelho 
34e87288f0SLuciano Coelho static struct wlcore_conf wl12xx_conf = {
35e87288f0SLuciano Coelho 	.sg = {
36e87288f0SLuciano Coelho 		.params = {
37133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
38133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
39133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
40133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
41133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
42133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
43133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
44133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
45133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
46133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
47133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
48133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
49133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
50133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
51133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
52133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
53133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
54133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
55133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
56133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
57133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
58133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
59133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
60133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
61133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
62133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
63e87288f0SLuciano Coelho 			/* active scan params */
64133b7326SGuy Mishol 			[WL12XX_CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
65133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
66133b7326SGuy Mishol 			[WL12XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
67e87288f0SLuciano Coelho 			/* passive scan params */
68133b7326SGuy Mishol 			[WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_A2DP_BR] = 800,
69133b7326SGuy Mishol 			[WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_A2DP_EDR] = 200,
70133b7326SGuy Mishol 			[WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_HV3] = 200,
71e87288f0SLuciano Coelho 			/* passive scan in dual antenna params */
72133b7326SGuy Mishol 			[WL12XX_CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
73133b7326SGuy Mishol 			[WL12XX_CONF_SG_BCN_HV3_COLL_THR_IN_PASSIVE_SCAN] = 0,
74133b7326SGuy Mishol 			[WL12XX_CONF_SG_TX_RX_PROTECT_BW_IN_PASSIVE_SCAN] = 0,
75e87288f0SLuciano Coelho 			/* general params */
76133b7326SGuy Mishol 			[WL12XX_CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
77133b7326SGuy Mishol 			[WL12XX_CONF_SG_ANTENNA_CONFIGURATION] = 0,
78133b7326SGuy Mishol 			[WL12XX_CONF_SG_BEACON_MISS_PERCENT] = 60,
79133b7326SGuy Mishol 			[WL12XX_CONF_SG_DHCP_TIME] = 5000,
80133b7326SGuy Mishol 			[WL12XX_CONF_SG_RXT] = 1200,
81133b7326SGuy Mishol 			[WL12XX_CONF_SG_TXT] = 1000,
82133b7326SGuy Mishol 			[WL12XX_CONF_SG_ADAPTIVE_RXT_TXT] = 1,
83133b7326SGuy Mishol 			[WL12XX_CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
84133b7326SGuy Mishol 			[WL12XX_CONF_SG_HV3_MAX_SERVED] = 6,
85133b7326SGuy Mishol 			[WL12XX_CONF_SG_PS_POLL_TIMEOUT] = 10,
86133b7326SGuy Mishol 			[WL12XX_CONF_SG_UPSD_TIMEOUT] = 10,
87133b7326SGuy Mishol 			[WL12XX_CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
88133b7326SGuy Mishol 			[WL12XX_CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
89133b7326SGuy Mishol 			[WL12XX_CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
90e87288f0SLuciano Coelho 			/* AP params */
91133b7326SGuy Mishol 			[WL12XX_CONF_AP_BEACON_MISS_TX] = 3,
92133b7326SGuy Mishol 			[WL12XX_CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
93133b7326SGuy Mishol 			[WL12XX_CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
94133b7326SGuy Mishol 			[WL12XX_CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
95133b7326SGuy Mishol 			[WL12XX_CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
96133b7326SGuy Mishol 			[WL12XX_CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
97e87288f0SLuciano Coelho 			/* CTS Diluting params */
98133b7326SGuy Mishol 			[WL12XX_CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
99133b7326SGuy Mishol 			[WL12XX_CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
100e87288f0SLuciano Coelho 		},
101e87288f0SLuciano Coelho 		.state = CONF_SG_PROTECTIVE,
102e87288f0SLuciano Coelho 	},
103e87288f0SLuciano Coelho 	.rx = {
104e87288f0SLuciano Coelho 		.rx_msdu_life_time           = 512000,
105e87288f0SLuciano Coelho 		.packet_detection_threshold  = 0,
106e87288f0SLuciano Coelho 		.ps_poll_timeout             = 15,
107e87288f0SLuciano Coelho 		.upsd_timeout                = 15,
108e87288f0SLuciano Coelho 		.rts_threshold               = IEEE80211_MAX_RTS_THRESHOLD,
109e87288f0SLuciano Coelho 		.rx_cca_threshold            = 0,
110e87288f0SLuciano Coelho 		.irq_blk_threshold           = 0xFFFF,
111e87288f0SLuciano Coelho 		.irq_pkt_threshold           = 0,
112e87288f0SLuciano Coelho 		.irq_timeout                 = 600,
113e87288f0SLuciano Coelho 		.queue_type                  = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
114e87288f0SLuciano Coelho 	},
115e87288f0SLuciano Coelho 	.tx = {
116e87288f0SLuciano Coelho 		.tx_energy_detection         = 0,
117e87288f0SLuciano Coelho 		.sta_rc_conf                 = {
118e87288f0SLuciano Coelho 			.enabled_rates       = 0,
119e87288f0SLuciano Coelho 			.short_retry_limit   = 10,
120e87288f0SLuciano Coelho 			.long_retry_limit    = 10,
121e87288f0SLuciano Coelho 			.aflags              = 0,
122e87288f0SLuciano Coelho 		},
123e87288f0SLuciano Coelho 		.ac_conf_count               = 4,
124e87288f0SLuciano Coelho 		.ac_conf                     = {
125e87288f0SLuciano Coelho 			[CONF_TX_AC_BE] = {
126e87288f0SLuciano Coelho 				.ac          = CONF_TX_AC_BE,
127e87288f0SLuciano Coelho 				.cw_min      = 15,
128e87288f0SLuciano Coelho 				.cw_max      = 63,
129e87288f0SLuciano Coelho 				.aifsn       = 3,
130e87288f0SLuciano Coelho 				.tx_op_limit = 0,
131e87288f0SLuciano Coelho 			},
132e87288f0SLuciano Coelho 			[CONF_TX_AC_BK] = {
133e87288f0SLuciano Coelho 				.ac          = CONF_TX_AC_BK,
134e87288f0SLuciano Coelho 				.cw_min      = 15,
135e87288f0SLuciano Coelho 				.cw_max      = 63,
136e87288f0SLuciano Coelho 				.aifsn       = 7,
137e87288f0SLuciano Coelho 				.tx_op_limit = 0,
138e87288f0SLuciano Coelho 			},
139e87288f0SLuciano Coelho 			[CONF_TX_AC_VI] = {
140e87288f0SLuciano Coelho 				.ac          = CONF_TX_AC_VI,
141e87288f0SLuciano Coelho 				.cw_min      = 15,
142e87288f0SLuciano Coelho 				.cw_max      = 63,
143e87288f0SLuciano Coelho 				.aifsn       = CONF_TX_AIFS_PIFS,
144e87288f0SLuciano Coelho 				.tx_op_limit = 3008,
145e87288f0SLuciano Coelho 			},
146e87288f0SLuciano Coelho 			[CONF_TX_AC_VO] = {
147e87288f0SLuciano Coelho 				.ac          = CONF_TX_AC_VO,
148e87288f0SLuciano Coelho 				.cw_min      = 15,
149e87288f0SLuciano Coelho 				.cw_max      = 63,
150e87288f0SLuciano Coelho 				.aifsn       = CONF_TX_AIFS_PIFS,
151e87288f0SLuciano Coelho 				.tx_op_limit = 1504,
152e87288f0SLuciano Coelho 			},
153e87288f0SLuciano Coelho 		},
154e87288f0SLuciano Coelho 		.max_tx_retries = 100,
155e87288f0SLuciano Coelho 		.ap_aging_period = 300,
156e87288f0SLuciano Coelho 		.tid_conf_count = 4,
157e87288f0SLuciano Coelho 		.tid_conf = {
158e87288f0SLuciano Coelho 			[CONF_TX_AC_BE] = {
159e87288f0SLuciano Coelho 				.queue_id    = CONF_TX_AC_BE,
160e87288f0SLuciano Coelho 				.channel_type = CONF_CHANNEL_TYPE_EDCF,
161e87288f0SLuciano Coelho 				.tsid        = CONF_TX_AC_BE,
162e87288f0SLuciano Coelho 				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
163e87288f0SLuciano Coelho 				.ack_policy  = CONF_ACK_POLICY_LEGACY,
164e87288f0SLuciano Coelho 				.apsd_conf   = {0, 0},
165e87288f0SLuciano Coelho 			},
166e87288f0SLuciano Coelho 			[CONF_TX_AC_BK] = {
167e87288f0SLuciano Coelho 				.queue_id    = CONF_TX_AC_BK,
168e87288f0SLuciano Coelho 				.channel_type = CONF_CHANNEL_TYPE_EDCF,
169e87288f0SLuciano Coelho 				.tsid        = CONF_TX_AC_BK,
170e87288f0SLuciano Coelho 				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
171e87288f0SLuciano Coelho 				.ack_policy  = CONF_ACK_POLICY_LEGACY,
172e87288f0SLuciano Coelho 				.apsd_conf   = {0, 0},
173e87288f0SLuciano Coelho 			},
174e87288f0SLuciano Coelho 			[CONF_TX_AC_VI] = {
175e87288f0SLuciano Coelho 				.queue_id    = CONF_TX_AC_VI,
176e87288f0SLuciano Coelho 				.channel_type = CONF_CHANNEL_TYPE_EDCF,
177e87288f0SLuciano Coelho 				.tsid        = CONF_TX_AC_VI,
178e87288f0SLuciano Coelho 				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
179e87288f0SLuciano Coelho 				.ack_policy  = CONF_ACK_POLICY_LEGACY,
180e87288f0SLuciano Coelho 				.apsd_conf   = {0, 0},
181e87288f0SLuciano Coelho 			},
182e87288f0SLuciano Coelho 			[CONF_TX_AC_VO] = {
183e87288f0SLuciano Coelho 				.queue_id    = CONF_TX_AC_VO,
184e87288f0SLuciano Coelho 				.channel_type = CONF_CHANNEL_TYPE_EDCF,
185e87288f0SLuciano Coelho 				.tsid        = CONF_TX_AC_VO,
186e87288f0SLuciano Coelho 				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
187e87288f0SLuciano Coelho 				.ack_policy  = CONF_ACK_POLICY_LEGACY,
188e87288f0SLuciano Coelho 				.apsd_conf   = {0, 0},
189e87288f0SLuciano Coelho 			},
190e87288f0SLuciano Coelho 		},
191e87288f0SLuciano Coelho 		.frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
192e87288f0SLuciano Coelho 		.tx_compl_timeout            = 700,
193e87288f0SLuciano Coelho 		.tx_compl_threshold          = 4,
194e87288f0SLuciano Coelho 		.basic_rate                  = CONF_HW_BIT_RATE_1MBPS,
195e87288f0SLuciano Coelho 		.basic_rate_5                = CONF_HW_BIT_RATE_6MBPS,
196e87288f0SLuciano Coelho 		.tmpl_short_retry_limit      = 10,
197e87288f0SLuciano Coelho 		.tmpl_long_retry_limit       = 10,
198e87288f0SLuciano Coelho 		.tx_watchdog_timeout         = 5000,
1990e810479SArik Nemtsov 		.slow_link_thold             = 3,
2000e810479SArik Nemtsov 		.fast_link_thold             = 10,
201e87288f0SLuciano Coelho 	},
202e87288f0SLuciano Coelho 	.conn = {
203e87288f0SLuciano Coelho 		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
204e87288f0SLuciano Coelho 		.listen_interval             = 1,
205e87288f0SLuciano Coelho 		.suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
206e87288f0SLuciano Coelho 		.suspend_listen_interval     = 3,
207e87288f0SLuciano Coelho 		.bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
208186b5a7cSEliad Peller 		.bcn_filt_ie_count           = 3,
209e87288f0SLuciano Coelho 		.bcn_filt_ie = {
210e87288f0SLuciano Coelho 			[0] = {
211e87288f0SLuciano Coelho 				.ie          = WLAN_EID_CHANNEL_SWITCH,
212e87288f0SLuciano Coelho 				.rule        = CONF_BCN_RULE_PASS_ON_APPEARANCE,
213e87288f0SLuciano Coelho 			},
214e87288f0SLuciano Coelho 			[1] = {
215e87288f0SLuciano Coelho 				.ie          = WLAN_EID_HT_OPERATION,
216e87288f0SLuciano Coelho 				.rule        = CONF_BCN_RULE_PASS_ON_CHANGE,
217e87288f0SLuciano Coelho 			},
218186b5a7cSEliad Peller 			[2] = {
219186b5a7cSEliad Peller 				.ie	     = WLAN_EID_ERP_INFO,
220186b5a7cSEliad Peller 				.rule	     = CONF_BCN_RULE_PASS_ON_CHANGE,
221186b5a7cSEliad Peller 			},
222e87288f0SLuciano Coelho 		},
2237b052214SIgal Chernobelsky 		.synch_fail_thold            = 12,
2247b052214SIgal Chernobelsky 		.bss_lose_timeout            = 400,
225e87288f0SLuciano Coelho 		.beacon_rx_timeout           = 10000,
226e87288f0SLuciano Coelho 		.broadcast_timeout           = 20000,
227e87288f0SLuciano Coelho 		.rx_broadcast_in_ps          = 1,
228e87288f0SLuciano Coelho 		.ps_poll_threshold           = 10,
229e87288f0SLuciano Coelho 		.bet_enable                  = CONF_BET_MODE_ENABLE,
230e87288f0SLuciano Coelho 		.bet_max_consecutive         = 50,
231e87288f0SLuciano Coelho 		.psm_entry_retries           = 8,
232e87288f0SLuciano Coelho 		.psm_exit_retries            = 16,
233e87288f0SLuciano Coelho 		.psm_entry_nullfunc_retries  = 3,
2340fc1d2e9SArik Nemtsov 		.dynamic_ps_timeout          = 1500,
235e87288f0SLuciano Coelho 		.forced_ps                   = false,
236e87288f0SLuciano Coelho 		.keep_alive_interval         = 55000,
237e87288f0SLuciano Coelho 		.max_listen_interval         = 20,
23866340e5bSArik Nemtsov 		.sta_sleep_auth              = WL1271_PSM_ILLEGAL,
2396d5a748dSRam Amrani 		.suspend_rx_ba_activity      = 0,
240e87288f0SLuciano Coelho 	},
241e87288f0SLuciano Coelho 	.itrim = {
242e87288f0SLuciano Coelho 		.enable = false,
243e87288f0SLuciano Coelho 		.timeout = 50000,
244e87288f0SLuciano Coelho 	},
245e87288f0SLuciano Coelho 	.pm_config = {
246e87288f0SLuciano Coelho 		.host_clk_settling_time = 5000,
247648f6ed9SLuciano Coelho 		.host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
248e87288f0SLuciano Coelho 	},
249e87288f0SLuciano Coelho 	.roam_trigger = {
250e87288f0SLuciano Coelho 		.trigger_pacing               = 1,
251e87288f0SLuciano Coelho 		.avg_weight_rssi_beacon       = 20,
252e87288f0SLuciano Coelho 		.avg_weight_rssi_data         = 10,
253e87288f0SLuciano Coelho 		.avg_weight_snr_beacon        = 20,
254e87288f0SLuciano Coelho 		.avg_weight_snr_data          = 10,
255e87288f0SLuciano Coelho 	},
256e87288f0SLuciano Coelho 	.scan = {
257e87288f0SLuciano Coelho 		.min_dwell_time_active        = 7500,
258e87288f0SLuciano Coelho 		.max_dwell_time_active        = 30000,
2595d3a1603SEyal Shapira 		.min_dwell_time_active_long   = 25000,
2605d3a1603SEyal Shapira 		.max_dwell_time_active_long   = 50000,
2617c482c10SEliad Peller 		.dwell_time_passive           = 100000,
2627c482c10SEliad Peller 		.dwell_time_dfs               = 150000,
263e87288f0SLuciano Coelho 		.num_probe_reqs               = 2,
264e87288f0SLuciano Coelho 		.split_scan_timeout           = 50000,
265e87288f0SLuciano Coelho 	},
266e87288f0SLuciano Coelho 	.sched_scan = {
267e87288f0SLuciano Coelho 		/*
268e87288f0SLuciano Coelho 		 * Values are in TU/1000 but since sched scan FW command
269e87288f0SLuciano Coelho 		 * params are in TUs rounding up may occur.
270e87288f0SLuciano Coelho 		 */
271e87288f0SLuciano Coelho 		.base_dwell_time		= 7500,
272e87288f0SLuciano Coelho 		.max_dwell_time_delta		= 22500,
273e87288f0SLuciano Coelho 		/* based on 250bits per probe @1Mbps */
274e87288f0SLuciano Coelho 		.dwell_time_delta_per_probe	= 2000,
275e87288f0SLuciano Coelho 		/* based on 250bits per probe @6Mbps (plus a bit more) */
276e87288f0SLuciano Coelho 		.dwell_time_delta_per_probe_5	= 350,
277e87288f0SLuciano Coelho 		.dwell_time_passive		= 100000,
278e87288f0SLuciano Coelho 		.dwell_time_dfs			= 150000,
279e87288f0SLuciano Coelho 		.num_probe_reqs			= 2,
280e87288f0SLuciano Coelho 		.rssi_threshold			= -90,
281e87288f0SLuciano Coelho 		.snr_threshold			= 0,
282e87288f0SLuciano Coelho 	},
283e87288f0SLuciano Coelho 	.ht = {
284e87288f0SLuciano Coelho 		.rx_ba_win_size = 8,
285e87288f0SLuciano Coelho 		.tx_ba_win_size = 64,
286e87288f0SLuciano Coelho 		.inactivity_timeout = 10000,
287e87288f0SLuciano Coelho 		.tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
288e87288f0SLuciano Coelho 	},
2895453dc10SLuciano Coelho 	/*
2905453dc10SLuciano Coelho 	 * Memory config for wl127x chips is given in the
2915453dc10SLuciano Coelho 	 * wl12xx_default_priv_conf struct. The below configuration is
2925453dc10SLuciano Coelho 	 * for wl128x chips.
2935453dc10SLuciano Coelho 	 */
2945453dc10SLuciano Coelho 	.mem = {
295e87288f0SLuciano Coelho 		.num_stations                 = 1,
296e87288f0SLuciano Coelho 		.ssid_profiles                = 1,
297e87288f0SLuciano Coelho 		.rx_block_num                 = 40,
298e87288f0SLuciano Coelho 		.tx_min_block_num             = 40,
299e87288f0SLuciano Coelho 		.dynamic_memory               = 1,
300e87288f0SLuciano Coelho 		.min_req_tx_blocks            = 45,
301e87288f0SLuciano Coelho 		.min_req_rx_blocks            = 22,
302e87288f0SLuciano Coelho 		.tx_min                       = 27,
303e87288f0SLuciano Coelho 	},
304e87288f0SLuciano Coelho 	.fm_coex = {
305e87288f0SLuciano Coelho 		.enable                       = true,
306e87288f0SLuciano Coelho 		.swallow_period               = 5,
307e87288f0SLuciano Coelho 		.n_divider_fref_set_1         = 0xff,       /* default */
308e87288f0SLuciano Coelho 		.n_divider_fref_set_2         = 12,
309836d3f20SVictor Goldenshtein 		.m_divider_fref_set_1         = 0xffff,
310836d3f20SVictor Goldenshtein 		.m_divider_fref_set_2         = 148,	    /* default */
311e87288f0SLuciano Coelho 		.coex_pll_stabilization_time  = 0xffffffff, /* default */
312e87288f0SLuciano Coelho 		.ldo_stabilization_time       = 0xffff,     /* default */
313e87288f0SLuciano Coelho 		.fm_disturbed_band_margin     = 0xff,       /* default */
314e87288f0SLuciano Coelho 		.swallow_clk_diff             = 0xff,       /* default */
315e87288f0SLuciano Coelho 	},
316e87288f0SLuciano Coelho 	.rx_streaming = {
317e87288f0SLuciano Coelho 		.duration                      = 150,
318e87288f0SLuciano Coelho 		.queues                        = 0x1,
319e87288f0SLuciano Coelho 		.interval                      = 20,
320e87288f0SLuciano Coelho 		.always                        = 0,
321e87288f0SLuciano Coelho 	},
322e87288f0SLuciano Coelho 	.fwlog = {
3239d8146d4SIdo Reis 		.mode                         = WL12XX_FWLOG_CONTINUOUS,
324e87288f0SLuciano Coelho 		.mem_blocks                   = 2,
325e87288f0SLuciano Coelho 		.severity                     = 0,
326e87288f0SLuciano Coelho 		.timestamp                    = WL12XX_FWLOG_TIMESTAMP_DISABLED,
3279d8146d4SIdo Reis 		.output                       = WL12XX_FWLOG_OUTPUT_DBG_PINS,
328e87288f0SLuciano Coelho 		.threshold                    = 0,
329e87288f0SLuciano Coelho 	},
330e87288f0SLuciano Coelho 	.rate = {
331e87288f0SLuciano Coelho 		.rate_retry_score = 32000,
332e87288f0SLuciano Coelho 		.per_add = 8192,
333e87288f0SLuciano Coelho 		.per_th1 = 2048,
334e87288f0SLuciano Coelho 		.per_th2 = 4096,
335e87288f0SLuciano Coelho 		.max_per = 8100,
336e87288f0SLuciano Coelho 		.inverse_curiosity_factor = 5,
337e87288f0SLuciano Coelho 		.tx_fail_low_th = 4,
338e87288f0SLuciano Coelho 		.tx_fail_high_th = 10,
339e87288f0SLuciano Coelho 		.per_alpha_shift = 4,
340e87288f0SLuciano Coelho 		.per_add_shift = 13,
341e87288f0SLuciano Coelho 		.per_beta1_shift = 10,
342e87288f0SLuciano Coelho 		.per_beta2_shift = 8,
343e87288f0SLuciano Coelho 		.rate_check_up = 2,
344e87288f0SLuciano Coelho 		.rate_check_down = 12,
345e87288f0SLuciano Coelho 		.rate_retry_policy = {
346e87288f0SLuciano Coelho 			0x00, 0x00, 0x00, 0x00, 0x00,
347e87288f0SLuciano Coelho 			0x00, 0x00, 0x00, 0x00, 0x00,
348e87288f0SLuciano Coelho 			0x00, 0x00, 0x00,
349e87288f0SLuciano Coelho 		},
350e87288f0SLuciano Coelho 	},
351e87288f0SLuciano Coelho 	.hangover = {
352e87288f0SLuciano Coelho 		.recover_time               = 0,
353e87288f0SLuciano Coelho 		.hangover_period            = 20,
354e87288f0SLuciano Coelho 		.dynamic_mode               = 1,
355e87288f0SLuciano Coelho 		.early_termination_mode     = 1,
356e87288f0SLuciano Coelho 		.max_period                 = 20,
357e87288f0SLuciano Coelho 		.min_period                 = 1,
358e87288f0SLuciano Coelho 		.increase_delta             = 1,
359e87288f0SLuciano Coelho 		.decrease_delta             = 2,
360e87288f0SLuciano Coelho 		.quiet_time                 = 4,
361e87288f0SLuciano Coelho 		.increase_time              = 1,
362e87288f0SLuciano Coelho 		.window_size                = 16,
363e87288f0SLuciano Coelho 	},
3647230341fSYair Shapira 	.recovery = {
3657230341fSYair Shapira 		.bug_on_recovery	    = 0,
3667230341fSYair Shapira 		.no_recovery		    = 0,
3677230341fSYair Shapira 	},
368e87288f0SLuciano Coelho };
369e87288f0SLuciano Coelho 
3705453dc10SLuciano Coelho static struct wl12xx_priv_conf wl12xx_default_priv_conf = {
3715453dc10SLuciano Coelho 	.rf = {
3725453dc10SLuciano Coelho 		.tx_per_channel_power_compensation_2 = {
3735453dc10SLuciano Coelho 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3745453dc10SLuciano Coelho 		},
3755453dc10SLuciano Coelho 		.tx_per_channel_power_compensation_5 = {
3765453dc10SLuciano Coelho 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3775453dc10SLuciano Coelho 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3785453dc10SLuciano Coelho 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3795453dc10SLuciano Coelho 		},
3805453dc10SLuciano Coelho 	},
3815453dc10SLuciano Coelho 	.mem_wl127x = {
3825453dc10SLuciano Coelho 		.num_stations                 = 1,
3835453dc10SLuciano Coelho 		.ssid_profiles                = 1,
3845453dc10SLuciano Coelho 		.rx_block_num                 = 70,
3855453dc10SLuciano Coelho 		.tx_min_block_num             = 40,
3865453dc10SLuciano Coelho 		.dynamic_memory               = 1,
3875453dc10SLuciano Coelho 		.min_req_tx_blocks            = 100,
3885453dc10SLuciano Coelho 		.min_req_rx_blocks            = 22,
3895453dc10SLuciano Coelho 		.tx_min                       = 27,
3905453dc10SLuciano Coelho 	},
3915453dc10SLuciano Coelho 
3925453dc10SLuciano Coelho };
393e87288f0SLuciano Coelho 
3943edab305SArik Nemtsov #define WL12XX_TX_HW_BLOCK_SPARE_DEFAULT        1
3953edab305SArik Nemtsov #define WL12XX_TX_HW_BLOCK_GEM_SPARE            2
396b3b4b4b8SArik Nemtsov #define WL12XX_TX_HW_BLOCK_SIZE                 252
3973edab305SArik Nemtsov 
39843a8bc5aSArik Nemtsov static const u8 wl12xx_rate_to_idx_2ghz[] = {
39943a8bc5aSArik Nemtsov 	/* MCS rates are used only with 11n */
40043a8bc5aSArik Nemtsov 	7,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */
40143a8bc5aSArik Nemtsov 	7,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */
40243a8bc5aSArik Nemtsov 	6,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */
40343a8bc5aSArik Nemtsov 	5,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */
40443a8bc5aSArik Nemtsov 	4,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */
40543a8bc5aSArik Nemtsov 	3,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */
40643a8bc5aSArik Nemtsov 	2,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */
40743a8bc5aSArik Nemtsov 	1,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */
40843a8bc5aSArik Nemtsov 	0,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */
40943a8bc5aSArik Nemtsov 
41043a8bc5aSArik Nemtsov 	11,                            /* WL12XX_CONF_HW_RXTX_RATE_54   */
41143a8bc5aSArik Nemtsov 	10,                            /* WL12XX_CONF_HW_RXTX_RATE_48   */
41243a8bc5aSArik Nemtsov 	9,                             /* WL12XX_CONF_HW_RXTX_RATE_36   */
41343a8bc5aSArik Nemtsov 	8,                             /* WL12XX_CONF_HW_RXTX_RATE_24   */
41443a8bc5aSArik Nemtsov 
41543a8bc5aSArik Nemtsov 	/* TI-specific rate */
41643a8bc5aSArik Nemtsov 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22   */
41743a8bc5aSArik Nemtsov 
41843a8bc5aSArik Nemtsov 	7,                             /* WL12XX_CONF_HW_RXTX_RATE_18   */
41943a8bc5aSArik Nemtsov 	6,                             /* WL12XX_CONF_HW_RXTX_RATE_12   */
42043a8bc5aSArik Nemtsov 	3,                             /* WL12XX_CONF_HW_RXTX_RATE_11   */
42143a8bc5aSArik Nemtsov 	5,                             /* WL12XX_CONF_HW_RXTX_RATE_9    */
42243a8bc5aSArik Nemtsov 	4,                             /* WL12XX_CONF_HW_RXTX_RATE_6    */
42343a8bc5aSArik Nemtsov 	2,                             /* WL12XX_CONF_HW_RXTX_RATE_5_5  */
42443a8bc5aSArik Nemtsov 	1,                             /* WL12XX_CONF_HW_RXTX_RATE_2    */
42543a8bc5aSArik Nemtsov 	0                              /* WL12XX_CONF_HW_RXTX_RATE_1    */
42643a8bc5aSArik Nemtsov };
42743a8bc5aSArik Nemtsov 
42843a8bc5aSArik Nemtsov static const u8 wl12xx_rate_to_idx_5ghz[] = {
42943a8bc5aSArik Nemtsov 	/* MCS rates are used only with 11n */
43043a8bc5aSArik Nemtsov 	7,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */
43143a8bc5aSArik Nemtsov 	7,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */
43243a8bc5aSArik Nemtsov 	6,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */
43343a8bc5aSArik Nemtsov 	5,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */
43443a8bc5aSArik Nemtsov 	4,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */
43543a8bc5aSArik Nemtsov 	3,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */
43643a8bc5aSArik Nemtsov 	2,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */
43743a8bc5aSArik Nemtsov 	1,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */
43843a8bc5aSArik Nemtsov 	0,                             /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */
43943a8bc5aSArik Nemtsov 
44043a8bc5aSArik Nemtsov 	7,                             /* WL12XX_CONF_HW_RXTX_RATE_54   */
44143a8bc5aSArik Nemtsov 	6,                             /* WL12XX_CONF_HW_RXTX_RATE_48   */
44243a8bc5aSArik Nemtsov 	5,                             /* WL12XX_CONF_HW_RXTX_RATE_36   */
44343a8bc5aSArik Nemtsov 	4,                             /* WL12XX_CONF_HW_RXTX_RATE_24   */
44443a8bc5aSArik Nemtsov 
44543a8bc5aSArik Nemtsov 	/* TI-specific rate */
44643a8bc5aSArik Nemtsov 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22   */
44743a8bc5aSArik Nemtsov 
44843a8bc5aSArik Nemtsov 	3,                             /* WL12XX_CONF_HW_RXTX_RATE_18   */
44943a8bc5aSArik Nemtsov 	2,                             /* WL12XX_CONF_HW_RXTX_RATE_12   */
45043a8bc5aSArik Nemtsov 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_11   */
45143a8bc5aSArik Nemtsov 	1,                             /* WL12XX_CONF_HW_RXTX_RATE_9    */
45243a8bc5aSArik Nemtsov 	0,                             /* WL12XX_CONF_HW_RXTX_RATE_6    */
45343a8bc5aSArik Nemtsov 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_5_5  */
45443a8bc5aSArik Nemtsov 	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_2    */
45543a8bc5aSArik Nemtsov 	CONF_HW_RXTX_RATE_UNSUPPORTED  /* WL12XX_CONF_HW_RXTX_RATE_1    */
45643a8bc5aSArik Nemtsov };
45743a8bc5aSArik Nemtsov 
45843a8bc5aSArik Nemtsov static const u8 *wl12xx_band_rate_to_idx[] = {
45957fbcce3SJohannes Berg 	[NL80211_BAND_2GHZ] = wl12xx_rate_to_idx_2ghz,
46057fbcce3SJohannes Berg 	[NL80211_BAND_5GHZ] = wl12xx_rate_to_idx_5ghz
46143a8bc5aSArik Nemtsov };
46243a8bc5aSArik Nemtsov 
46343a8bc5aSArik Nemtsov enum wl12xx_hw_rates {
46443a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI = 0,
46543a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS7,
46643a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS6,
46743a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS5,
46843a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS4,
46943a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS3,
47043a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS2,
47143a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS1,
47243a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MCS0,
47343a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_54,
47443a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_48,
47543a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_36,
47643a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_24,
47743a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_22,
47843a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_18,
47943a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_12,
48043a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_11,
48143a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_9,
48243a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_6,
48343a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_5_5,
48443a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_2,
48543a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_1,
48643a8bc5aSArik Nemtsov 	WL12XX_CONF_HW_RXTX_RATE_MAX,
48743a8bc5aSArik Nemtsov };
4883edab305SArik Nemtsov 
48925a43d78SLuciano Coelho static struct wlcore_partition_set wl12xx_ptable[PART_TABLE_LEN] = {
49025a43d78SLuciano Coelho 	[PART_DOWN] = {
49125a43d78SLuciano Coelho 		.mem = {
49225a43d78SLuciano Coelho 			.start = 0x00000000,
49325a43d78SLuciano Coelho 			.size  = 0x000177c0
49425a43d78SLuciano Coelho 		},
49525a43d78SLuciano Coelho 		.reg = {
49625a43d78SLuciano Coelho 			.start = REGISTERS_BASE,
49725a43d78SLuciano Coelho 			.size  = 0x00008800
49825a43d78SLuciano Coelho 		},
49925a43d78SLuciano Coelho 		.mem2 = {
50025a43d78SLuciano Coelho 			.start = 0x00000000,
50125a43d78SLuciano Coelho 			.size  = 0x00000000
50225a43d78SLuciano Coelho 		},
50325a43d78SLuciano Coelho 		.mem3 = {
50425a43d78SLuciano Coelho 			.start = 0x00000000,
50525a43d78SLuciano Coelho 			.size  = 0x00000000
50625a43d78SLuciano Coelho 		},
50725a43d78SLuciano Coelho 	},
50825a43d78SLuciano Coelho 
50900782136SLuciano Coelho 	[PART_BOOT] = { /* in wl12xx we can use a mix of work and down
51000782136SLuciano Coelho 			 * partition here */
51100782136SLuciano Coelho 		.mem = {
51200782136SLuciano Coelho 			.start = 0x00040000,
51300782136SLuciano Coelho 			.size  = 0x00014fc0
51400782136SLuciano Coelho 		},
51500782136SLuciano Coelho 		.reg = {
51600782136SLuciano Coelho 			.start = REGISTERS_BASE,
51700782136SLuciano Coelho 			.size  = 0x00008800
51800782136SLuciano Coelho 		},
51900782136SLuciano Coelho 		.mem2 = {
52000782136SLuciano Coelho 			.start = 0x00000000,
52100782136SLuciano Coelho 			.size  = 0x00000000
52200782136SLuciano Coelho 		},
52300782136SLuciano Coelho 		.mem3 = {
52400782136SLuciano Coelho 			.start = 0x00000000,
52500782136SLuciano Coelho 			.size  = 0x00000000
52600782136SLuciano Coelho 		},
52700782136SLuciano Coelho 	},
52800782136SLuciano Coelho 
52925a43d78SLuciano Coelho 	[PART_WORK] = {
53025a43d78SLuciano Coelho 		.mem = {
53125a43d78SLuciano Coelho 			.start = 0x00040000,
53225a43d78SLuciano Coelho 			.size  = 0x00014fc0
53325a43d78SLuciano Coelho 		},
53425a43d78SLuciano Coelho 		.reg = {
53525a43d78SLuciano Coelho 			.start = REGISTERS_BASE,
53625a43d78SLuciano Coelho 			.size  = 0x0000a000
53725a43d78SLuciano Coelho 		},
53825a43d78SLuciano Coelho 		.mem2 = {
53925a43d78SLuciano Coelho 			.start = 0x003004f8,
54025a43d78SLuciano Coelho 			.size  = 0x00000004
54125a43d78SLuciano Coelho 		},
54225a43d78SLuciano Coelho 		.mem3 = {
5436fe813e3SGuy Mishol 			.start = 0x00000000,
5446fe813e3SGuy Mishol 			.size  = 0x00040404
54525a43d78SLuciano Coelho 		},
54625a43d78SLuciano Coelho 	},
54725a43d78SLuciano Coelho 
54825a43d78SLuciano Coelho 	[PART_DRPW] = {
54925a43d78SLuciano Coelho 		.mem = {
55025a43d78SLuciano Coelho 			.start = 0x00040000,
55125a43d78SLuciano Coelho 			.size  = 0x00014fc0
55225a43d78SLuciano Coelho 		},
55325a43d78SLuciano Coelho 		.reg = {
55425a43d78SLuciano Coelho 			.start = DRPW_BASE,
55525a43d78SLuciano Coelho 			.size  = 0x00006000
55625a43d78SLuciano Coelho 		},
55725a43d78SLuciano Coelho 		.mem2 = {
55825a43d78SLuciano Coelho 			.start = 0x00000000,
55925a43d78SLuciano Coelho 			.size  = 0x00000000
56025a43d78SLuciano Coelho 		},
56125a43d78SLuciano Coelho 		.mem3 = {
56225a43d78SLuciano Coelho 			.start = 0x00000000,
56325a43d78SLuciano Coelho 			.size  = 0x00000000
56425a43d78SLuciano Coelho 		}
56525a43d78SLuciano Coelho 	}
56625a43d78SLuciano Coelho };
56725a43d78SLuciano Coelho 
56800782136SLuciano Coelho static const int wl12xx_rtable[REG_TABLE_LEN] = {
56900782136SLuciano Coelho 	[REG_ECPU_CONTROL]		= WL12XX_REG_ECPU_CONTROL,
57000782136SLuciano Coelho 	[REG_INTERRUPT_NO_CLEAR]	= WL12XX_REG_INTERRUPT_NO_CLEAR,
57100782136SLuciano Coelho 	[REG_INTERRUPT_ACK]		= WL12XX_REG_INTERRUPT_ACK,
57200782136SLuciano Coelho 	[REG_COMMAND_MAILBOX_PTR]	= WL12XX_REG_COMMAND_MAILBOX_PTR,
57300782136SLuciano Coelho 	[REG_EVENT_MAILBOX_PTR]		= WL12XX_REG_EVENT_MAILBOX_PTR,
57400782136SLuciano Coelho 	[REG_INTERRUPT_TRIG]		= WL12XX_REG_INTERRUPT_TRIG,
57500782136SLuciano Coelho 	[REG_INTERRUPT_MASK]		= WL12XX_REG_INTERRUPT_MASK,
57600782136SLuciano Coelho 	[REG_PC_ON_RECOVERY]		= WL12XX_SCR_PAD4,
57700782136SLuciano Coelho 	[REG_CHIP_ID_B]			= WL12XX_CHIP_ID_B,
57800782136SLuciano Coelho 	[REG_CMD_MBOX_ADDRESS]		= WL12XX_CMD_MBOX_ADDRESS,
57900782136SLuciano Coelho 
58000782136SLuciano Coelho 	/* data access memory addresses, used with partition translation */
58100782136SLuciano Coelho 	[REG_SLV_MEM_DATA]		= WL1271_SLV_MEM_DATA,
58200782136SLuciano Coelho 	[REG_SLV_REG_DATA]		= WL1271_SLV_REG_DATA,
58300782136SLuciano Coelho 
58400782136SLuciano Coelho 	/* raw data access memory addresses */
58500782136SLuciano Coelho 	[REG_RAW_FW_STATUS_ADDR]	= FW_STATUS_ADDR,
58600782136SLuciano Coelho };
58700782136SLuciano Coelho 
5886f7dd16cSLuciano Coelho /* TODO: maybe move to a new header file? */
58966ef60adSLuciano Coelho #define WL127X_FW_NAME_MULTI	"ti-connectivity/wl127x-fw-5-mr.bin"
59066ef60adSLuciano Coelho #define WL127X_FW_NAME_SINGLE	"ti-connectivity/wl127x-fw-5-sr.bin"
59166ef60adSLuciano Coelho #define WL127X_PLT_FW_NAME	"ti-connectivity/wl127x-fw-5-plt.bin"
5926f7dd16cSLuciano Coelho 
59366ef60adSLuciano Coelho #define WL128X_FW_NAME_MULTI	"ti-connectivity/wl128x-fw-5-mr.bin"
59466ef60adSLuciano Coelho #define WL128X_FW_NAME_SINGLE	"ti-connectivity/wl128x-fw-5-sr.bin"
59566ef60adSLuciano Coelho #define WL128X_PLT_FW_NAME	"ti-connectivity/wl128x-fw-5-plt.bin"
5966f7dd16cSLuciano Coelho 
wl127x_prepare_read(struct wl1271 * wl,u32 rx_desc,u32 len)597eb96f841SIdo Yariv static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len)
598b14684a0SLuciano Coelho {
599eb96f841SIdo Yariv 	int ret;
600eb96f841SIdo Yariv 
601986f3aa1SLuciano Coelho 	if (wl->chip.id != CHIP_ID_128X_PG20) {
602b14684a0SLuciano Coelho 		struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
6032e07d028SIdo Yariv 		struct wl12xx_priv *priv = wl->priv;
604b14684a0SLuciano Coelho 
605b14684a0SLuciano Coelho 		/*
606b14684a0SLuciano Coelho 		 * Choose the block we want to read
607b14684a0SLuciano Coelho 		 * For aggregated packets, only the first memory block
608b14684a0SLuciano Coelho 		 * should be retrieved. The FW takes care of the rest.
609b14684a0SLuciano Coelho 		 */
610b14684a0SLuciano Coelho 		u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK;
611b14684a0SLuciano Coelho 
6122e07d028SIdo Yariv 		priv->rx_mem_addr->addr = (mem_block << 8) +
613b14684a0SLuciano Coelho 			le32_to_cpu(wl_mem_map->packet_memory_pool_start);
614b14684a0SLuciano Coelho 
6152e07d028SIdo Yariv 		priv->rx_mem_addr->addr_extra = priv->rx_mem_addr->addr + 4;
616b14684a0SLuciano Coelho 
6172e07d028SIdo Yariv 		ret = wlcore_write(wl, WL1271_SLV_REG_DATA, priv->rx_mem_addr,
6182e07d028SIdo Yariv 				   sizeof(*priv->rx_mem_addr), false);
619eb96f841SIdo Yariv 		if (ret < 0)
620eb96f841SIdo Yariv 			return ret;
621b14684a0SLuciano Coelho 	}
622eb96f841SIdo Yariv 
623eb96f841SIdo Yariv 	return 0;
624b14684a0SLuciano Coelho }
625b14684a0SLuciano Coelho 
wl12xx_identify_chip(struct wl1271 * wl)6266f7dd16cSLuciano Coelho static int wl12xx_identify_chip(struct wl1271 *wl)
6276f7dd16cSLuciano Coelho {
6286f7dd16cSLuciano Coelho 	int ret = 0;
6296f7dd16cSLuciano Coelho 
6306f7dd16cSLuciano Coelho 	switch (wl->chip.id) {
631986f3aa1SLuciano Coelho 	case CHIP_ID_127X_PG10:
6326f7dd16cSLuciano Coelho 		wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
6336f7dd16cSLuciano Coelho 			       wl->chip.id);
6346f7dd16cSLuciano Coelho 
6352c0133a4SArik Nemtsov 		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
6363df74f46SYoni Divinsky 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
63718eab430SEliad Peller 			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
6383ea186d1SArik Nemtsov 			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
6396f7dd16cSLuciano Coelho 		wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
6406f7dd16cSLuciano Coelho 		wl->mr_fw_name = WL127X_FW_NAME_MULTI;
6415453dc10SLuciano Coelho 		memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
6425453dc10SLuciano Coelho 		       sizeof(wl->conf.mem));
643b14684a0SLuciano Coelho 
644b14684a0SLuciano Coelho 		/* read data preparation is only needed by wl127x */
645b14684a0SLuciano Coelho 		wl->ops->prepare_read = wl127x_prepare_read;
646b14684a0SLuciano Coelho 
6478675f9abSLuciano Coelho 		wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER,
6488675f9abSLuciano Coelho 			      WL127X_IFTYPE_SR_VER,  WL127X_MAJOR_SR_VER,
6498675f9abSLuciano Coelho 			      WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER,
6508675f9abSLuciano Coelho 			      WL127X_IFTYPE_MR_VER,  WL127X_MAJOR_MR_VER,
6518675f9abSLuciano Coelho 			      WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER);
6526f7dd16cSLuciano Coelho 		break;
6536f7dd16cSLuciano Coelho 
654986f3aa1SLuciano Coelho 	case CHIP_ID_127X_PG20:
6556f7dd16cSLuciano Coelho 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
6566f7dd16cSLuciano Coelho 			     wl->chip.id);
6576f7dd16cSLuciano Coelho 
6582c0133a4SArik Nemtsov 		wl->quirks |= WLCORE_QUIRK_LEGACY_NVS |
6593df74f46SYoni Divinsky 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
66018eab430SEliad Peller 			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
6613ea186d1SArik Nemtsov 			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
6626f7dd16cSLuciano Coelho 		wl->plt_fw_name = WL127X_PLT_FW_NAME;
6636f7dd16cSLuciano Coelho 		wl->sr_fw_name = WL127X_FW_NAME_SINGLE;
6646f7dd16cSLuciano Coelho 		wl->mr_fw_name = WL127X_FW_NAME_MULTI;
6655453dc10SLuciano Coelho 		memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x,
6665453dc10SLuciano Coelho 		       sizeof(wl->conf.mem));
667b14684a0SLuciano Coelho 
668b14684a0SLuciano Coelho 		/* read data preparation is only needed by wl127x */
669b14684a0SLuciano Coelho 		wl->ops->prepare_read = wl127x_prepare_read;
670b14684a0SLuciano Coelho 
6718675f9abSLuciano Coelho 		wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER,
6728675f9abSLuciano Coelho 			      WL127X_IFTYPE_SR_VER,  WL127X_MAJOR_SR_VER,
6738675f9abSLuciano Coelho 			      WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER,
6748675f9abSLuciano Coelho 			      WL127X_IFTYPE_MR_VER,  WL127X_MAJOR_MR_VER,
6758675f9abSLuciano Coelho 			      WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER);
6766f7dd16cSLuciano Coelho 		break;
6776f7dd16cSLuciano Coelho 
678986f3aa1SLuciano Coelho 	case CHIP_ID_128X_PG20:
6796f7dd16cSLuciano Coelho 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
6806f7dd16cSLuciano Coelho 			     wl->chip.id);
6816f7dd16cSLuciano Coelho 		wl->plt_fw_name = WL128X_PLT_FW_NAME;
6826f7dd16cSLuciano Coelho 		wl->sr_fw_name = WL128X_FW_NAME_SINGLE;
6836f7dd16cSLuciano Coelho 		wl->mr_fw_name = WL128X_FW_NAME_MULTI;
684b5d6d9b2SLuciano Coelho 
685b5d6d9b2SLuciano Coelho 		/* wl128x requires TX blocksize alignment */
6862c0133a4SArik Nemtsov 		wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
6873df74f46SYoni Divinsky 			      WLCORE_QUIRK_DUAL_PROBE_TMPL |
68818eab430SEliad Peller 			      WLCORE_QUIRK_TKIP_HEADER_SPACE |
6893ea186d1SArik Nemtsov 			      WLCORE_QUIRK_AP_ZERO_SESSION_ID;
690b5d6d9b2SLuciano Coelho 
6918675f9abSLuciano Coelho 		wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER,
6928675f9abSLuciano Coelho 			      WL128X_IFTYPE_SR_VER,  WL128X_MAJOR_SR_VER,
6938675f9abSLuciano Coelho 			      WL128X_SUBTYPE_SR_VER, WL128X_MINOR_SR_VER,
6948675f9abSLuciano Coelho 			      WL128X_IFTYPE_MR_VER,  WL128X_MAJOR_MR_VER,
6958675f9abSLuciano Coelho 			      WL128X_SUBTYPE_MR_VER, WL128X_MINOR_MR_VER);
6966f7dd16cSLuciano Coelho 		break;
697986f3aa1SLuciano Coelho 	case CHIP_ID_128X_PG10:
6986f7dd16cSLuciano Coelho 	default:
6996f7dd16cSLuciano Coelho 		wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
7006f7dd16cSLuciano Coelho 		ret = -ENODEV;
7016f7dd16cSLuciano Coelho 		goto out;
7026f7dd16cSLuciano Coelho 	}
7036f7dd16cSLuciano Coelho 
704c83cb803SIgal Chernobelsky 	wl->fw_mem_block_size = 256;
705c83cb803SIgal Chernobelsky 	wl->fwlog_end = 0x2000000;
706c83cb803SIgal Chernobelsky 
70778e28062SEliad Peller 	/* common settings */
70878e28062SEliad Peller 	wl->scan_templ_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY;
70978e28062SEliad Peller 	wl->scan_templ_id_5 = CMD_TEMPL_APP_PROBE_REQ_5_LEGACY;
71078e28062SEliad Peller 	wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
71178e28062SEliad Peller 	wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
7120a1c720cSEliad Peller 	wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ;
713d21553f8SIgal Chernobelsky 	wl->ba_rx_session_count_max = WL12XX_RX_BA_MAX_SESSIONS;
7146f7dd16cSLuciano Coelho out:
7156f7dd16cSLuciano Coelho 	return ret;
7166f7dd16cSLuciano Coelho }
7176f7dd16cSLuciano Coelho 
wl12xx_top_reg_write(struct wl1271 * wl,int addr,u16 val)718f1a26e63SIdo Yariv static int __must_check wl12xx_top_reg_write(struct wl1271 *wl, int addr,
719f1a26e63SIdo Yariv 					     u16 val)
720dd5512ebSLuciano Coelho {
721b0f0ad39SIdo Yariv 	int ret;
722b0f0ad39SIdo Yariv 
723dd5512ebSLuciano Coelho 	/* write address >> 1 + 0x30000 to OCP_POR_CTR */
724dd5512ebSLuciano Coelho 	addr = (addr >> 1) + 0x30000;
725b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr);
726b0f0ad39SIdo Yariv 	if (ret < 0)
727b0f0ad39SIdo Yariv 		goto out;
728dd5512ebSLuciano Coelho 
729dd5512ebSLuciano Coelho 	/* write value to OCP_POR_WDATA */
730b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_OCP_DATA_WRITE, val);
731b0f0ad39SIdo Yariv 	if (ret < 0)
732b0f0ad39SIdo Yariv 		goto out;
733dd5512ebSLuciano Coelho 
734dd5512ebSLuciano Coelho 	/* write 1 to OCP_CMD */
735b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE);
736b0f0ad39SIdo Yariv 	if (ret < 0)
737b0f0ad39SIdo Yariv 		goto out;
738b0f0ad39SIdo Yariv 
739b0f0ad39SIdo Yariv out:
740b0f0ad39SIdo Yariv 	return ret;
741dd5512ebSLuciano Coelho }
742dd5512ebSLuciano Coelho 
wl12xx_top_reg_read(struct wl1271 * wl,int addr,u16 * out)743f1a26e63SIdo Yariv static int __must_check wl12xx_top_reg_read(struct wl1271 *wl, int addr,
744f1a26e63SIdo Yariv 					    u16 *out)
745dd5512ebSLuciano Coelho {
746dd5512ebSLuciano Coelho 	u32 val;
747dd5512ebSLuciano Coelho 	int timeout = OCP_CMD_LOOP;
7486134323fSIdo Yariv 	int ret;
749dd5512ebSLuciano Coelho 
750dd5512ebSLuciano Coelho 	/* write address >> 1 + 0x30000 to OCP_POR_CTR */
751dd5512ebSLuciano Coelho 	addr = (addr >> 1) + 0x30000;
752b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr);
753b0f0ad39SIdo Yariv 	if (ret < 0)
754b0f0ad39SIdo Yariv 		return ret;
755dd5512ebSLuciano Coelho 
756dd5512ebSLuciano Coelho 	/* write 2 to OCP_CMD */
757b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ);
758b0f0ad39SIdo Yariv 	if (ret < 0)
759b0f0ad39SIdo Yariv 		return ret;
760dd5512ebSLuciano Coelho 
761dd5512ebSLuciano Coelho 	/* poll for data ready */
762dd5512ebSLuciano Coelho 	do {
7636134323fSIdo Yariv 		ret = wlcore_read32(wl, WL12XX_OCP_DATA_READ, &val);
7646134323fSIdo Yariv 		if (ret < 0)
7656134323fSIdo Yariv 			return ret;
766dd5512ebSLuciano Coelho 	} while (!(val & OCP_READY_MASK) && --timeout);
767dd5512ebSLuciano Coelho 
768dd5512ebSLuciano Coelho 	if (!timeout) {
769dd5512ebSLuciano Coelho 		wl1271_warning("Top register access timed out.");
7706134323fSIdo Yariv 		return -ETIMEDOUT;
771dd5512ebSLuciano Coelho 	}
772dd5512ebSLuciano Coelho 
773dd5512ebSLuciano Coelho 	/* check data status and return if OK */
7746134323fSIdo Yariv 	if ((val & OCP_STATUS_MASK) != OCP_STATUS_OK) {
775dd5512ebSLuciano Coelho 		wl1271_warning("Top register access returned error.");
7766134323fSIdo Yariv 		return -EIO;
777dd5512ebSLuciano Coelho 	}
7786134323fSIdo Yariv 
7796134323fSIdo Yariv 	if (out)
7806134323fSIdo Yariv 		*out = val & 0xffff;
7816134323fSIdo Yariv 
7826134323fSIdo Yariv 	return 0;
783dd5512ebSLuciano Coelho }
784dd5512ebSLuciano Coelho 
wl128x_switch_tcxo_to_fref(struct wl1271 * wl)785dd5512ebSLuciano Coelho static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
786dd5512ebSLuciano Coelho {
787dd5512ebSLuciano Coelho 	u16 spare_reg;
7886134323fSIdo Yariv 	int ret;
789dd5512ebSLuciano Coelho 
790dd5512ebSLuciano Coelho 	/* Mask bits [2] & [8:4] in the sys_clk_cfg register */
7916134323fSIdo Yariv 	ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg);
7926134323fSIdo Yariv 	if (ret < 0)
7936134323fSIdo Yariv 		return ret;
7946134323fSIdo Yariv 
795dd5512ebSLuciano Coelho 	if (spare_reg == 0xFFFF)
796dd5512ebSLuciano Coelho 		return -EFAULT;
797dd5512ebSLuciano Coelho 	spare_reg |= (BIT(3) | BIT(5) | BIT(6));
798b0f0ad39SIdo Yariv 	ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
799b0f0ad39SIdo Yariv 	if (ret < 0)
800b0f0ad39SIdo Yariv 		return ret;
801dd5512ebSLuciano Coelho 
802dd5512ebSLuciano Coelho 	/* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */
803b0f0ad39SIdo Yariv 	ret = wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG,
804dd5512ebSLuciano Coelho 				   WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
805b0f0ad39SIdo Yariv 	if (ret < 0)
806b0f0ad39SIdo Yariv 		return ret;
807dd5512ebSLuciano Coelho 
808dd5512ebSLuciano Coelho 	/* Delay execution for 15msec, to let the HW settle */
809dd5512ebSLuciano Coelho 	mdelay(15);
810dd5512ebSLuciano Coelho 
811dd5512ebSLuciano Coelho 	return 0;
812dd5512ebSLuciano Coelho }
813dd5512ebSLuciano Coelho 
wl128x_is_tcxo_valid(struct wl1271 * wl)814dd5512ebSLuciano Coelho static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
815dd5512ebSLuciano Coelho {
816dd5512ebSLuciano Coelho 	u16 tcxo_detection;
8176134323fSIdo Yariv 	int ret;
818dd5512ebSLuciano Coelho 
8196134323fSIdo Yariv 	ret = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG, &tcxo_detection);
8206134323fSIdo Yariv 	if (ret < 0)
8216134323fSIdo Yariv 		return false;
8226134323fSIdo Yariv 
823dd5512ebSLuciano Coelho 	if (tcxo_detection & TCXO_DET_FAILED)
824dd5512ebSLuciano Coelho 		return false;
825dd5512ebSLuciano Coelho 
826dd5512ebSLuciano Coelho 	return true;
827dd5512ebSLuciano Coelho }
828dd5512ebSLuciano Coelho 
wl128x_is_fref_valid(struct wl1271 * wl)829dd5512ebSLuciano Coelho static bool wl128x_is_fref_valid(struct wl1271 *wl)
830dd5512ebSLuciano Coelho {
831dd5512ebSLuciano Coelho 	u16 fref_detection;
8326134323fSIdo Yariv 	int ret;
833dd5512ebSLuciano Coelho 
8346134323fSIdo Yariv 	ret = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG, &fref_detection);
8356134323fSIdo Yariv 	if (ret < 0)
8366134323fSIdo Yariv 		return false;
8376134323fSIdo Yariv 
838dd5512ebSLuciano Coelho 	if (fref_detection & FREF_CLK_DETECT_FAIL)
839dd5512ebSLuciano Coelho 		return false;
840dd5512ebSLuciano Coelho 
841dd5512ebSLuciano Coelho 	return true;
842dd5512ebSLuciano Coelho }
843dd5512ebSLuciano Coelho 
wl128x_manually_configure_mcs_pll(struct wl1271 * wl)844dd5512ebSLuciano Coelho static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl)
845dd5512ebSLuciano Coelho {
846b0f0ad39SIdo Yariv 	int ret;
847dd5512ebSLuciano Coelho 
848b0f0ad39SIdo Yariv 	ret = wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
849b0f0ad39SIdo Yariv 	if (ret < 0)
850b0f0ad39SIdo Yariv 		goto out;
851b0f0ad39SIdo Yariv 
852b0f0ad39SIdo Yariv 	ret = wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
853b0f0ad39SIdo Yariv 	if (ret < 0)
854b0f0ad39SIdo Yariv 		goto out;
855b0f0ad39SIdo Yariv 
856b0f0ad39SIdo Yariv 	ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG,
857b0f0ad39SIdo Yariv 				   MCS_PLL_CONFIG_REG_VAL);
858b0f0ad39SIdo Yariv 
859b0f0ad39SIdo Yariv out:
860b0f0ad39SIdo Yariv 	return ret;
861dd5512ebSLuciano Coelho }
862dd5512ebSLuciano Coelho 
wl128x_configure_mcs_pll(struct wl1271 * wl,int clk)863dd5512ebSLuciano Coelho static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
864dd5512ebSLuciano Coelho {
865dd5512ebSLuciano Coelho 	u16 spare_reg;
866dd5512ebSLuciano Coelho 	u16 pll_config;
867dd5512ebSLuciano Coelho 	u8 input_freq;
868a5d751bbSLuciano Coelho 	struct wl12xx_priv *priv = wl->priv;
8696134323fSIdo Yariv 	int ret;
870dd5512ebSLuciano Coelho 
871dd5512ebSLuciano Coelho 	/* Mask bits [3:1] in the sys_clk_cfg register */
8726134323fSIdo Yariv 	ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg);
8736134323fSIdo Yariv 	if (ret < 0)
8746134323fSIdo Yariv 		return ret;
8756134323fSIdo Yariv 
876dd5512ebSLuciano Coelho 	if (spare_reg == 0xFFFF)
877dd5512ebSLuciano Coelho 		return -EFAULT;
878dd5512ebSLuciano Coelho 	spare_reg |= BIT(2);
879b0f0ad39SIdo Yariv 	ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg);
880b0f0ad39SIdo Yariv 	if (ret < 0)
881b0f0ad39SIdo Yariv 		return ret;
882dd5512ebSLuciano Coelho 
883dd5512ebSLuciano Coelho 	/* Handle special cases of the TCXO clock */
884a5d751bbSLuciano Coelho 	if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
885a5d751bbSLuciano Coelho 	    priv->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
886dd5512ebSLuciano Coelho 		return wl128x_manually_configure_mcs_pll(wl);
887dd5512ebSLuciano Coelho 
888dd5512ebSLuciano Coelho 	/* Set the input frequency according to the selected clock source */
889dd5512ebSLuciano Coelho 	input_freq = (clk & 1) + 1;
890dd5512ebSLuciano Coelho 
8916134323fSIdo Yariv 	ret = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG, &pll_config);
8926134323fSIdo Yariv 	if (ret < 0)
8936134323fSIdo Yariv 		return ret;
8946134323fSIdo Yariv 
895dd5512ebSLuciano Coelho 	if (pll_config == 0xFFFF)
896dd5512ebSLuciano Coelho 		return -EFAULT;
897dd5512ebSLuciano Coelho 	pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT);
898dd5512ebSLuciano Coelho 	pll_config |= MCS_PLL_ENABLE_HP;
899b0f0ad39SIdo Yariv 	ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config);
900dd5512ebSLuciano Coelho 
901b0f0ad39SIdo Yariv 	return ret;
902dd5512ebSLuciano Coelho }
903dd5512ebSLuciano Coelho 
904dd5512ebSLuciano Coelho /*
905dd5512ebSLuciano Coelho  * WL128x has two clocks input - TCXO and FREF.
906dd5512ebSLuciano Coelho  * TCXO is the main clock of the device, while FREF is used to sync
907dd5512ebSLuciano Coelho  * between the GPS and the cellular modem.
908dd5512ebSLuciano Coelho  * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used
909dd5512ebSLuciano Coelho  * as the WLAN/BT main clock.
910dd5512ebSLuciano Coelho  */
wl128x_boot_clk(struct wl1271 * wl,int * selected_clock)911dd5512ebSLuciano Coelho static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
912dd5512ebSLuciano Coelho {
913a5d751bbSLuciano Coelho 	struct wl12xx_priv *priv = wl->priv;
914dd5512ebSLuciano Coelho 	u16 sys_clk_cfg;
9156134323fSIdo Yariv 	int ret;
916dd5512ebSLuciano Coelho 
917dd5512ebSLuciano Coelho 	/* For XTAL-only modes, FREF will be used after switching from TCXO */
918a5d751bbSLuciano Coelho 	if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
919a5d751bbSLuciano Coelho 	    priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
920dd5512ebSLuciano Coelho 		if (!wl128x_switch_tcxo_to_fref(wl))
921dd5512ebSLuciano Coelho 			return -EINVAL;
922dd5512ebSLuciano Coelho 		goto fref_clk;
923dd5512ebSLuciano Coelho 	}
924dd5512ebSLuciano Coelho 
925dd5512ebSLuciano Coelho 	/* Query the HW, to determine which clock source we should use */
9266134323fSIdo Yariv 	ret = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG, &sys_clk_cfg);
9276134323fSIdo Yariv 	if (ret < 0)
9286134323fSIdo Yariv 		return ret;
9296134323fSIdo Yariv 
930dd5512ebSLuciano Coelho 	if (sys_clk_cfg == 0xFFFF)
931dd5512ebSLuciano Coelho 		return -EINVAL;
932dd5512ebSLuciano Coelho 	if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF)
933dd5512ebSLuciano Coelho 		goto fref_clk;
934dd5512ebSLuciano Coelho 
935dd5512ebSLuciano Coelho 	/* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */
936a5d751bbSLuciano Coelho 	if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
937a5d751bbSLuciano Coelho 	    priv->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
938dd5512ebSLuciano Coelho 		if (!wl128x_switch_tcxo_to_fref(wl))
939dd5512ebSLuciano Coelho 			return -EINVAL;
940dd5512ebSLuciano Coelho 		goto fref_clk;
941dd5512ebSLuciano Coelho 	}
942dd5512ebSLuciano Coelho 
943dd5512ebSLuciano Coelho 	/* TCXO clock is selected */
944dd5512ebSLuciano Coelho 	if (!wl128x_is_tcxo_valid(wl))
945dd5512ebSLuciano Coelho 		return -EINVAL;
946a5d751bbSLuciano Coelho 	*selected_clock = priv->tcxo_clock;
947dd5512ebSLuciano Coelho 	goto config_mcs_pll;
948dd5512ebSLuciano Coelho 
949dd5512ebSLuciano Coelho fref_clk:
950dd5512ebSLuciano Coelho 	/* FREF clock is selected */
951dd5512ebSLuciano Coelho 	if (!wl128x_is_fref_valid(wl))
952dd5512ebSLuciano Coelho 		return -EINVAL;
953a5d751bbSLuciano Coelho 	*selected_clock = priv->ref_clock;
954dd5512ebSLuciano Coelho 
955dd5512ebSLuciano Coelho config_mcs_pll:
956dd5512ebSLuciano Coelho 	return wl128x_configure_mcs_pll(wl, *selected_clock);
957dd5512ebSLuciano Coelho }
958dd5512ebSLuciano Coelho 
wl127x_boot_clk(struct wl1271 * wl)959dd5512ebSLuciano Coelho static int wl127x_boot_clk(struct wl1271 *wl)
960dd5512ebSLuciano Coelho {
961a5d751bbSLuciano Coelho 	struct wl12xx_priv *priv = wl->priv;
962dd5512ebSLuciano Coelho 	u32 pause;
963dd5512ebSLuciano Coelho 	u32 clk;
9646134323fSIdo Yariv 	int ret;
965dd5512ebSLuciano Coelho 
966dd5512ebSLuciano Coelho 	if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3)
967dd5512ebSLuciano Coelho 		wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION;
968dd5512ebSLuciano Coelho 
969a5d751bbSLuciano Coelho 	if (priv->ref_clock == CONF_REF_CLK_19_2_E ||
970a5d751bbSLuciano Coelho 	    priv->ref_clock == CONF_REF_CLK_38_4_E ||
971a5d751bbSLuciano Coelho 	    priv->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
972dd5512ebSLuciano Coelho 		/* ref clk: 19.2/38.4/38.4-XTAL */
973dd5512ebSLuciano Coelho 		clk = 0x3;
974a5d751bbSLuciano Coelho 	else if (priv->ref_clock == CONF_REF_CLK_26_E ||
975e16de2c4SGrant Erickson 		 priv->ref_clock == CONF_REF_CLK_26_M_XTAL ||
976a5d751bbSLuciano Coelho 		 priv->ref_clock == CONF_REF_CLK_52_E)
977dd5512ebSLuciano Coelho 		/* ref clk: 26/52 */
978dd5512ebSLuciano Coelho 		clk = 0x5;
979dd5512ebSLuciano Coelho 	else
980dd5512ebSLuciano Coelho 		return -EINVAL;
981dd5512ebSLuciano Coelho 
982a5d751bbSLuciano Coelho 	if (priv->ref_clock != CONF_REF_CLK_19_2_E) {
983dd5512ebSLuciano Coelho 		u16 val;
984dd5512ebSLuciano Coelho 		/* Set clock type (open drain) */
9856134323fSIdo Yariv 		ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE, &val);
9866134323fSIdo Yariv 		if (ret < 0)
9876134323fSIdo Yariv 			goto out;
9886134323fSIdo Yariv 
989dd5512ebSLuciano Coelho 		val &= FREF_CLK_TYPE_BITS;
990b0f0ad39SIdo Yariv 		ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
991b0f0ad39SIdo Yariv 		if (ret < 0)
992b0f0ad39SIdo Yariv 			goto out;
993dd5512ebSLuciano Coelho 
994dd5512ebSLuciano Coelho 		/* Set clock pull mode (no pull) */
9956134323fSIdo Yariv 		ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL, &val);
9966134323fSIdo Yariv 		if (ret < 0)
9976134323fSIdo Yariv 			goto out;
9986134323fSIdo Yariv 
999dd5512ebSLuciano Coelho 		val |= NO_PULL;
1000b0f0ad39SIdo Yariv 		ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val);
1001b0f0ad39SIdo Yariv 		if (ret < 0)
1002b0f0ad39SIdo Yariv 			goto out;
1003dd5512ebSLuciano Coelho 	} else {
1004dd5512ebSLuciano Coelho 		u16 val;
1005dd5512ebSLuciano Coelho 		/* Set clock polarity */
10066134323fSIdo Yariv 		ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY, &val);
10076134323fSIdo Yariv 		if (ret < 0)
10086134323fSIdo Yariv 			goto out;
10096134323fSIdo Yariv 
1010dd5512ebSLuciano Coelho 		val &= FREF_CLK_POLARITY_BITS;
1011dd5512ebSLuciano Coelho 		val |= CLK_REQ_OUTN_SEL;
1012b0f0ad39SIdo Yariv 		ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val);
1013b0f0ad39SIdo Yariv 		if (ret < 0)
1014b0f0ad39SIdo Yariv 			goto out;
1015dd5512ebSLuciano Coelho 	}
1016dd5512ebSLuciano Coelho 
1017b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_PLL_PARAMETERS, clk);
1018b0f0ad39SIdo Yariv 	if (ret < 0)
1019b0f0ad39SIdo Yariv 		goto out;
1020dd5512ebSLuciano Coelho 
10216134323fSIdo Yariv 	ret = wlcore_read32(wl, WL12XX_PLL_PARAMETERS, &pause);
10226134323fSIdo Yariv 	if (ret < 0)
10236134323fSIdo Yariv 		goto out;
1024dd5512ebSLuciano Coelho 
1025dd5512ebSLuciano Coelho 	wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause);
1026dd5512ebSLuciano Coelho 
1027dd5512ebSLuciano Coelho 	pause &= ~(WU_COUNTER_PAUSE_VAL);
1028dd5512ebSLuciano Coelho 	pause |= WU_COUNTER_PAUSE_VAL;
1029b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause);
1030dd5512ebSLuciano Coelho 
10316134323fSIdo Yariv out:
10326134323fSIdo Yariv 	return ret;
1033dd5512ebSLuciano Coelho }
1034dd5512ebSLuciano Coelho 
wl1271_boot_soft_reset(struct wl1271 * wl)1035dd5512ebSLuciano Coelho static int wl1271_boot_soft_reset(struct wl1271 *wl)
1036dd5512ebSLuciano Coelho {
1037dd5512ebSLuciano Coelho 	unsigned long timeout;
1038dd5512ebSLuciano Coelho 	u32 boot_data;
10396134323fSIdo Yariv 	int ret = 0;
1040dd5512ebSLuciano Coelho 
1041dd5512ebSLuciano Coelho 	/* perform soft reset */
1042b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
1043b0f0ad39SIdo Yariv 	if (ret < 0)
1044b0f0ad39SIdo Yariv 		goto out;
1045dd5512ebSLuciano Coelho 
1046dd5512ebSLuciano Coelho 	/* SOFT_RESET is self clearing */
1047dd5512ebSLuciano Coelho 	timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
1048dd5512ebSLuciano Coelho 	while (1) {
10496134323fSIdo Yariv 		ret = wlcore_read32(wl, WL12XX_SLV_SOFT_RESET, &boot_data);
10506134323fSIdo Yariv 		if (ret < 0)
10516134323fSIdo Yariv 			goto out;
10526134323fSIdo Yariv 
1053dd5512ebSLuciano Coelho 		wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
1054dd5512ebSLuciano Coelho 		if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
1055dd5512ebSLuciano Coelho 			break;
1056dd5512ebSLuciano Coelho 
1057dd5512ebSLuciano Coelho 		if (time_after(jiffies, timeout)) {
1058dd5512ebSLuciano Coelho 			/* 1.2 check pWhalBus->uSelfClearTime if the
1059dd5512ebSLuciano Coelho 			 * timeout was reached */
1060dd5512ebSLuciano Coelho 			wl1271_error("soft reset timeout");
1061dd5512ebSLuciano Coelho 			return -1;
1062dd5512ebSLuciano Coelho 		}
1063dd5512ebSLuciano Coelho 
1064dd5512ebSLuciano Coelho 		udelay(SOFT_RESET_STALL_TIME);
1065dd5512ebSLuciano Coelho 	}
1066dd5512ebSLuciano Coelho 
1067dd5512ebSLuciano Coelho 	/* disable Rx/Tx */
1068b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_ENABLE, 0x0);
1069b0f0ad39SIdo Yariv 	if (ret < 0)
1070b0f0ad39SIdo Yariv 		goto out;
1071dd5512ebSLuciano Coelho 
1072dd5512ebSLuciano Coelho 	/* disable auto calibration on start*/
1073b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_SPARE_A2, 0xffff);
1074dd5512ebSLuciano Coelho 
10756134323fSIdo Yariv out:
10766134323fSIdo Yariv 	return ret;
1077dd5512ebSLuciano Coelho }
1078dd5512ebSLuciano Coelho 
wl12xx_pre_boot(struct wl1271 * wl)1079dd5512ebSLuciano Coelho static int wl12xx_pre_boot(struct wl1271 *wl)
1080dd5512ebSLuciano Coelho {
1081a5d751bbSLuciano Coelho 	struct wl12xx_priv *priv = wl->priv;
1082dd5512ebSLuciano Coelho 	int ret = 0;
1083dd5512ebSLuciano Coelho 	u32 clk;
1084dd5512ebSLuciano Coelho 	int selected_clock = -1;
1085dd5512ebSLuciano Coelho 
1086986f3aa1SLuciano Coelho 	if (wl->chip.id == CHIP_ID_128X_PG20) {
1087dd5512ebSLuciano Coelho 		ret = wl128x_boot_clk(wl, &selected_clock);
1088dd5512ebSLuciano Coelho 		if (ret < 0)
1089dd5512ebSLuciano Coelho 			goto out;
1090dd5512ebSLuciano Coelho 	} else {
1091dd5512ebSLuciano Coelho 		ret = wl127x_boot_clk(wl);
1092dd5512ebSLuciano Coelho 		if (ret < 0)
1093dd5512ebSLuciano Coelho 			goto out;
1094dd5512ebSLuciano Coelho 	}
1095dd5512ebSLuciano Coelho 
1096dd5512ebSLuciano Coelho 	/* Continue the ELP wake up sequence */
1097b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
1098b0f0ad39SIdo Yariv 	if (ret < 0)
1099b0f0ad39SIdo Yariv 		goto out;
1100b0f0ad39SIdo Yariv 
1101dd5512ebSLuciano Coelho 	udelay(500);
1102dd5512ebSLuciano Coelho 
1103b0f0ad39SIdo Yariv 	ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
1104b0f0ad39SIdo Yariv 	if (ret < 0)
1105b0f0ad39SIdo Yariv 		goto out;
1106dd5512ebSLuciano Coelho 
1107dd5512ebSLuciano Coelho 	/* Read-modify-write DRPW_SCRATCH_START register (see next state)
1108dd5512ebSLuciano Coelho 	   to be used by DRPw FW. The RTRIM value will be added by the FW
1109dd5512ebSLuciano Coelho 	   before taking DRPw out of reset */
1110dd5512ebSLuciano Coelho 
11116134323fSIdo Yariv 	ret = wlcore_read32(wl, WL12XX_DRPW_SCRATCH_START, &clk);
11126134323fSIdo Yariv 	if (ret < 0)
11136134323fSIdo Yariv 		goto out;
1114dd5512ebSLuciano Coelho 
1115dd5512ebSLuciano Coelho 	wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
1116dd5512ebSLuciano Coelho 
1117986f3aa1SLuciano Coelho 	if (wl->chip.id == CHIP_ID_128X_PG20)
1118dd5512ebSLuciano Coelho 		clk |= ((selected_clock & 0x3) << 1) << 4;
1119dd5512ebSLuciano Coelho 	else
1120a5d751bbSLuciano Coelho 		clk |= (priv->ref_clock << 1) << 4;
1121dd5512ebSLuciano Coelho 
1122b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_DRPW_SCRATCH_START, clk);
1123b0f0ad39SIdo Yariv 	if (ret < 0)
1124b0f0ad39SIdo Yariv 		goto out;
1125dd5512ebSLuciano Coelho 
1126b0f0ad39SIdo Yariv 	ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]);
1127b0f0ad39SIdo Yariv 	if (ret < 0)
1128b0f0ad39SIdo Yariv 		goto out;
1129dd5512ebSLuciano Coelho 
1130dd5512ebSLuciano Coelho 	/* Disable interrupts */
1131b0f0ad39SIdo Yariv 	ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
1132b0f0ad39SIdo Yariv 	if (ret < 0)
1133b0f0ad39SIdo Yariv 		goto out;
1134dd5512ebSLuciano Coelho 
1135dd5512ebSLuciano Coelho 	ret = wl1271_boot_soft_reset(wl);
1136dd5512ebSLuciano Coelho 	if (ret < 0)
1137dd5512ebSLuciano Coelho 		goto out;
1138dd5512ebSLuciano Coelho 
1139dd5512ebSLuciano Coelho out:
1140dd5512ebSLuciano Coelho 	return ret;
1141dd5512ebSLuciano Coelho }
1142dd5512ebSLuciano Coelho 
wl12xx_pre_upload(struct wl1271 * wl)11436134323fSIdo Yariv static int wl12xx_pre_upload(struct wl1271 *wl)
1144dd5512ebSLuciano Coelho {
11456134323fSIdo Yariv 	u32 tmp;
11466134323fSIdo Yariv 	u16 polarity;
11476134323fSIdo Yariv 	int ret;
1148dd5512ebSLuciano Coelho 
1149dd5512ebSLuciano Coelho 	/* write firmware's last address (ie. it's length) to
1150dd5512ebSLuciano Coelho 	 * ACX_EEPROMLESS_IND_REG */
1151dd5512ebSLuciano Coelho 	wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG");
1152dd5512ebSLuciano Coelho 
1153b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND);
1154b0f0ad39SIdo Yariv 	if (ret < 0)
1155b0f0ad39SIdo Yariv 		goto out;
1156dd5512ebSLuciano Coelho 
11576134323fSIdo Yariv 	ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp);
11586134323fSIdo Yariv 	if (ret < 0)
11596134323fSIdo Yariv 		goto out;
1160dd5512ebSLuciano Coelho 
1161dd5512ebSLuciano Coelho 	wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
1162dd5512ebSLuciano Coelho 
1163dd5512ebSLuciano Coelho 	/* 6. read the EEPROM parameters */
11646134323fSIdo Yariv 	ret = wlcore_read32(wl, WL12XX_SCR_PAD2, &tmp);
11656134323fSIdo Yariv 	if (ret < 0)
11666134323fSIdo Yariv 		goto out;
1167dd5512ebSLuciano Coelho 
1168dd5512ebSLuciano Coelho 	/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
1169dd5512ebSLuciano Coelho 	 * to upload_fw) */
1170dd5512ebSLuciano Coelho 
1171986f3aa1SLuciano Coelho 	if (wl->chip.id == CHIP_ID_128X_PG20) {
1172b0f0ad39SIdo Yariv 		ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA);
1173b0f0ad39SIdo Yariv 		if (ret < 0)
1174b0f0ad39SIdo Yariv 			goto out;
1175b0f0ad39SIdo Yariv 	}
1176dd5512ebSLuciano Coelho 
11774a6c789bSYoni Divinsky 	/* polarity must be set before the firmware is loaded */
11786134323fSIdo Yariv 	ret = wl12xx_top_reg_read(wl, OCP_REG_POLARITY, &polarity);
11796134323fSIdo Yariv 	if (ret < 0)
11806134323fSIdo Yariv 		goto out;
1181dd5512ebSLuciano Coelho 
1182dd5512ebSLuciano Coelho 	/* We use HIGH polarity, so unset the LOW bit */
1183dd5512ebSLuciano Coelho 	polarity &= ~POLARITY_LOW;
1184b0f0ad39SIdo Yariv 	ret = wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity);
1185dd5512ebSLuciano Coelho 
11866134323fSIdo Yariv out:
11876134323fSIdo Yariv 	return ret;
11884a6c789bSYoni Divinsky }
11894a6c789bSYoni Divinsky 
wl12xx_enable_interrupts(struct wl1271 * wl)1190b0f0ad39SIdo Yariv static int wl12xx_enable_interrupts(struct wl1271 *wl)
11914a6c789bSYoni Divinsky {
1192b0f0ad39SIdo Yariv 	int ret;
1193b0f0ad39SIdo Yariv 
1194b0f0ad39SIdo Yariv 	ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
1195b0f0ad39SIdo Yariv 			       WL12XX_ACX_ALL_EVENTS_VECTOR);
1196b0f0ad39SIdo Yariv 	if (ret < 0)
1197b0f0ad39SIdo Yariv 		goto out;
1198dd5512ebSLuciano Coelho 
1199dd5512ebSLuciano Coelho 	wlcore_enable_interrupts(wl);
1200b0f0ad39SIdo Yariv 	ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
1201f5755fe9SIdo Reis 			       WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK));
1202b0f0ad39SIdo Yariv 	if (ret < 0)
1203a8311c8aSIdo Yariv 		goto disable_interrupts;
1204dd5512ebSLuciano Coelho 
1205b0f0ad39SIdo Yariv 	ret = wlcore_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL);
1206a8311c8aSIdo Yariv 	if (ret < 0)
1207a8311c8aSIdo Yariv 		goto disable_interrupts;
1208a8311c8aSIdo Yariv 
1209a8311c8aSIdo Yariv 	return ret;
1210a8311c8aSIdo Yariv 
1211a8311c8aSIdo Yariv disable_interrupts:
1212a8311c8aSIdo Yariv 	wlcore_disable_interrupts(wl);
1213b0f0ad39SIdo Yariv 
1214b0f0ad39SIdo Yariv out:
1215b0f0ad39SIdo Yariv 	return ret;
1216dd5512ebSLuciano Coelho }
1217dd5512ebSLuciano Coelho 
wl12xx_boot(struct wl1271 * wl)1218dd5512ebSLuciano Coelho static int wl12xx_boot(struct wl1271 *wl)
1219dd5512ebSLuciano Coelho {
1220dd5512ebSLuciano Coelho 	int ret;
1221dd5512ebSLuciano Coelho 
1222dd5512ebSLuciano Coelho 	ret = wl12xx_pre_boot(wl);
1223dd5512ebSLuciano Coelho 	if (ret < 0)
1224dd5512ebSLuciano Coelho 		goto out;
1225dd5512ebSLuciano Coelho 
1226dd5512ebSLuciano Coelho 	ret = wlcore_boot_upload_nvs(wl);
1227dd5512ebSLuciano Coelho 	if (ret < 0)
1228dd5512ebSLuciano Coelho 		goto out;
1229dd5512ebSLuciano Coelho 
12306134323fSIdo Yariv 	ret = wl12xx_pre_upload(wl);
12316134323fSIdo Yariv 	if (ret < 0)
12326134323fSIdo Yariv 		goto out;
1233dd5512ebSLuciano Coelho 
1234dd5512ebSLuciano Coelho 	ret = wlcore_boot_upload_firmware(wl);
1235dd5512ebSLuciano Coelho 	if (ret < 0)
1236dd5512ebSLuciano Coelho 		goto out;
1237dd5512ebSLuciano Coelho 
1238c50a2825SEliad Peller 	wl->event_mask = BSS_LOSE_EVENT_ID |
1239c50a2825SEliad Peller 		REGAINED_BSS_EVENT_ID |
1240c50a2825SEliad Peller 		SCAN_COMPLETE_EVENT_ID |
1241c50a2825SEliad Peller 		ROLE_STOP_COMPLETE_EVENT_ID |
1242c50a2825SEliad Peller 		RSSI_SNR_TRIGGER_0_EVENT_ID |
1243c50a2825SEliad Peller 		PSPOLL_DELIVERY_FAILURE_EVENT_ID |
1244c50a2825SEliad Peller 		SOFT_GEMINI_SENSE_EVENT_ID |
1245c50a2825SEliad Peller 		PERIODIC_SCAN_REPORT_EVENT_ID |
1246c50a2825SEliad Peller 		PERIODIC_SCAN_COMPLETE_EVENT_ID |
1247c50a2825SEliad Peller 		DUMMY_PACKET_EVENT_ID |
1248c50a2825SEliad Peller 		PEER_REMOVE_COMPLETE_EVENT_ID |
1249c50a2825SEliad Peller 		BA_SESSION_RX_CONSTRAINT_EVENT_ID |
1250c50a2825SEliad Peller 		REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
1251c50a2825SEliad Peller 		INACTIVE_STA_EVENT_ID |
1252c50a2825SEliad Peller 		CHANNEL_SWITCH_COMPLETE_EVENT_ID;
1253c50a2825SEliad Peller 
125471e996beSEliad Peller 	wl->ap_event_mask = MAX_TX_RETRY_EVENT_ID;
125571e996beSEliad Peller 
1256dd5512ebSLuciano Coelho 	ret = wlcore_boot_run_firmware(wl);
1257dd5512ebSLuciano Coelho 	if (ret < 0)
1258dd5512ebSLuciano Coelho 		goto out;
1259dd5512ebSLuciano Coelho 
1260b0f0ad39SIdo Yariv 	ret = wl12xx_enable_interrupts(wl);
1261dd5512ebSLuciano Coelho 
1262dd5512ebSLuciano Coelho out:
1263dd5512ebSLuciano Coelho 	return ret;
1264dd5512ebSLuciano Coelho }
1265dd5512ebSLuciano Coelho 
wl12xx_trigger_cmd(struct wl1271 * wl,int cmd_box_addr,void * buf,size_t len)1266eb96f841SIdo Yariv static int wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
12675d10b195SArik Nemtsov 			       void *buf, size_t len)
1268f16ff758SLuciano Coelho {
1269eb96f841SIdo Yariv 	int ret;
1270eb96f841SIdo Yariv 
1271eb96f841SIdo Yariv 	ret = wlcore_write(wl, cmd_box_addr, buf, len, false);
1272eb96f841SIdo Yariv 	if (ret < 0)
1273eb96f841SIdo Yariv 		return ret;
1274eb96f841SIdo Yariv 
1275b0f0ad39SIdo Yariv 	ret = wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD);
1276eb96f841SIdo Yariv 
1277eb96f841SIdo Yariv 	return ret;
1278f16ff758SLuciano Coelho }
1279f16ff758SLuciano Coelho 
wl12xx_ack_event(struct wl1271 * wl)1280b0f0ad39SIdo Yariv static int wl12xx_ack_event(struct wl1271 *wl)
1281f16ff758SLuciano Coelho {
1282b0f0ad39SIdo Yariv 	return wlcore_write_reg(wl, REG_INTERRUPT_TRIG,
1283b0f0ad39SIdo Yariv 				WL12XX_INTR_TRIG_EVENT_ACK);
1284f16ff758SLuciano Coelho }
1285f16ff758SLuciano Coelho 
wl12xx_calc_tx_blocks(struct wl1271 * wl,u32 len,u32 spare_blks)1286b3b4b4b8SArik Nemtsov static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
1287b3b4b4b8SArik Nemtsov {
1288b3b4b4b8SArik Nemtsov 	u32 blk_size = WL12XX_TX_HW_BLOCK_SIZE;
1289b3b4b4b8SArik Nemtsov 	u32 align_len = wlcore_calc_packet_alignment(wl, len);
1290b3b4b4b8SArik Nemtsov 
1291b3b4b4b8SArik Nemtsov 	return (align_len + blk_size - 1) / blk_size + spare_blks;
1292b3b4b4b8SArik Nemtsov }
1293b3b4b4b8SArik Nemtsov 
12944a3b97eeSArik Nemtsov static void
wl12xx_set_tx_desc_blocks(struct wl1271 * wl,struct wl1271_tx_hw_descr * desc,u32 blks,u32 spare_blks)12954a3b97eeSArik Nemtsov wl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
12964a3b97eeSArik Nemtsov 			  u32 blks, u32 spare_blks)
12974a3b97eeSArik Nemtsov {
1298986f3aa1SLuciano Coelho 	if (wl->chip.id == CHIP_ID_128X_PG20) {
12994a3b97eeSArik Nemtsov 		desc->wl128x_mem.total_mem_blocks = blks;
13004a3b97eeSArik Nemtsov 	} else {
13014a3b97eeSArik Nemtsov 		desc->wl127x_mem.extra_blocks = spare_blks;
13024a3b97eeSArik Nemtsov 		desc->wl127x_mem.total_mem_blocks = blks;
13034a3b97eeSArik Nemtsov 	}
13044a3b97eeSArik Nemtsov }
13054a3b97eeSArik Nemtsov 
13066f266e91SArik Nemtsov static void
wl12xx_set_tx_desc_data_len(struct wl1271 * wl,struct wl1271_tx_hw_descr * desc,struct sk_buff * skb)13076f266e91SArik Nemtsov wl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
13086f266e91SArik Nemtsov 			    struct sk_buff *skb)
13096f266e91SArik Nemtsov {
13106f266e91SArik Nemtsov 	u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len);
13116f266e91SArik Nemtsov 
1312986f3aa1SLuciano Coelho 	if (wl->chip.id == CHIP_ID_128X_PG20) {
13136f266e91SArik Nemtsov 		desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
13146f266e91SArik Nemtsov 		desc->length = cpu_to_le16(aligned_len >> 2);
13156f266e91SArik Nemtsov 
13166f266e91SArik Nemtsov 		wl1271_debug(DEBUG_TX,
13176f266e91SArik Nemtsov 			     "tx_fill_hdr: hlid: %d len: %d life: %d mem: %d extra: %d",
13186f266e91SArik Nemtsov 			     desc->hlid,
13196f266e91SArik Nemtsov 			     le16_to_cpu(desc->length),
13206f266e91SArik Nemtsov 			     le16_to_cpu(desc->life_time),
13216f266e91SArik Nemtsov 			     desc->wl128x_mem.total_mem_blocks,
13226f266e91SArik Nemtsov 			     desc->wl128x_mem.extra_bytes);
13236f266e91SArik Nemtsov 	} else {
13246f266e91SArik Nemtsov 		/* calculate number of padding bytes */
13256f266e91SArik Nemtsov 		int pad = aligned_len - skb->len;
13266f266e91SArik Nemtsov 		desc->tx_attr |=
13276f266e91SArik Nemtsov 			cpu_to_le16(pad << TX_HW_ATTR_OFST_LAST_WORD_PAD);
13286f266e91SArik Nemtsov 
13296f266e91SArik Nemtsov 		/* Store the aligned length in terms of words */
13306f266e91SArik Nemtsov 		desc->length = cpu_to_le16(aligned_len >> 2);
13316f266e91SArik Nemtsov 
13326f266e91SArik Nemtsov 		wl1271_debug(DEBUG_TX,
13336f266e91SArik Nemtsov 			     "tx_fill_hdr: pad: %d hlid: %d len: %d life: %d mem: %d",
13346f266e91SArik Nemtsov 			     pad, desc->hlid,
13356f266e91SArik Nemtsov 			     le16_to_cpu(desc->length),
13366f266e91SArik Nemtsov 			     le16_to_cpu(desc->life_time),
13376f266e91SArik Nemtsov 			     desc->wl127x_mem.total_mem_blocks);
13386f266e91SArik Nemtsov 	}
13396f266e91SArik Nemtsov }
13406f266e91SArik Nemtsov 
1341cd70f6a4SArik Nemtsov static enum wl_rx_buf_align
wl12xx_get_rx_buf_align(struct wl1271 * wl,u32 rx_desc)1342cd70f6a4SArik Nemtsov wl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
1343cd70f6a4SArik Nemtsov {
1344cd70f6a4SArik Nemtsov 	if (rx_desc & RX_BUF_UNALIGNED_PAYLOAD)
1345cd70f6a4SArik Nemtsov 		return WLCORE_RX_BUF_UNALIGNED;
1346cd70f6a4SArik Nemtsov 
1347cd70f6a4SArik Nemtsov 	return WLCORE_RX_BUF_ALIGNED;
1348cd70f6a4SArik Nemtsov }
1349cd70f6a4SArik Nemtsov 
wl12xx_get_rx_packet_len(struct wl1271 * wl,void * rx_data,u32 data_len)13504158149cSArik Nemtsov static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
13514158149cSArik Nemtsov 				    u32 data_len)
13524158149cSArik Nemtsov {
13534158149cSArik Nemtsov 	struct wl1271_rx_descriptor *desc = rx_data;
13544158149cSArik Nemtsov 
13554158149cSArik Nemtsov 	/* invalid packet */
13564158149cSArik Nemtsov 	if (data_len < sizeof(*desc) ||
13574158149cSArik Nemtsov 	    data_len < sizeof(*desc) + desc->pad_len)
13584158149cSArik Nemtsov 		return 0;
13594158149cSArik Nemtsov 
13604158149cSArik Nemtsov 	return data_len - sizeof(*desc) - desc->pad_len;
13614158149cSArik Nemtsov }
13624158149cSArik Nemtsov 
wl12xx_tx_delayed_compl(struct wl1271 * wl)1363045b9b5fSIdo Yariv static int wl12xx_tx_delayed_compl(struct wl1271 *wl)
136453d67a50SArik Nemtsov {
136575fb4df7SEliad Peller 	if (wl->fw_status->tx_results_counter ==
13660afd04e5SArik Nemtsov 	    (wl->tx_results_count & 0xff))
1367045b9b5fSIdo Yariv 		return 0;
136853d67a50SArik Nemtsov 
1369045b9b5fSIdo Yariv 	return wlcore_tx_complete(wl);
137053d67a50SArik Nemtsov }
137153d67a50SArik Nemtsov 
wl12xx_hw_init(struct wl1271 * wl)13729d68d1eeSLuciano Coelho static int wl12xx_hw_init(struct wl1271 *wl)
13739d68d1eeSLuciano Coelho {
13749d68d1eeSLuciano Coelho 	int ret;
13759d68d1eeSLuciano Coelho 
1376986f3aa1SLuciano Coelho 	if (wl->chip.id == CHIP_ID_128X_PG20) {
13779d68d1eeSLuciano Coelho 		u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
13789d68d1eeSLuciano Coelho 
13799d68d1eeSLuciano Coelho 		ret = wl128x_cmd_general_parms(wl);
13809d68d1eeSLuciano Coelho 		if (ret < 0)
13819d68d1eeSLuciano Coelho 			goto out;
1382ff324317SYair Shapira 
1383ff324317SYair Shapira 		/*
1384ff324317SYair Shapira 		 * If we are in calibrator based auto detect then we got the FEM nr
1385ff324317SYair Shapira 		 * in wl->fem_manuf. No need to continue further
1386ff324317SYair Shapira 		 */
1387ff324317SYair Shapira 		if (wl->plt_mode == PLT_FEM_DETECT)
1388ff324317SYair Shapira 			goto out;
1389ff324317SYair Shapira 
13909d68d1eeSLuciano Coelho 		ret = wl128x_cmd_radio_parms(wl);
13919d68d1eeSLuciano Coelho 		if (ret < 0)
13929d68d1eeSLuciano Coelho 			goto out;
13939d68d1eeSLuciano Coelho 
13949d68d1eeSLuciano Coelho 		if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)
13959d68d1eeSLuciano Coelho 			/* Enable SDIO padding */
13969d68d1eeSLuciano Coelho 			host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
13979d68d1eeSLuciano Coelho 
13989d68d1eeSLuciano Coelho 		/* Must be before wl1271_acx_init_mem_config() */
13999d68d1eeSLuciano Coelho 		ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
14009d68d1eeSLuciano Coelho 		if (ret < 0)
14019d68d1eeSLuciano Coelho 			goto out;
14029d68d1eeSLuciano Coelho 	} else {
14039d68d1eeSLuciano Coelho 		ret = wl1271_cmd_general_parms(wl);
14049d68d1eeSLuciano Coelho 		if (ret < 0)
14059d68d1eeSLuciano Coelho 			goto out;
1406ff324317SYair Shapira 
1407ff324317SYair Shapira 		/*
1408ff324317SYair Shapira 		 * If we are in calibrator based auto detect then we got the FEM nr
1409ff324317SYair Shapira 		 * in wl->fem_manuf. No need to continue further
1410ff324317SYair Shapira 		 */
1411ff324317SYair Shapira 		if (wl->plt_mode == PLT_FEM_DETECT)
1412ff324317SYair Shapira 			goto out;
1413ff324317SYair Shapira 
14149d68d1eeSLuciano Coelho 		ret = wl1271_cmd_radio_parms(wl);
14159d68d1eeSLuciano Coelho 		if (ret < 0)
14169d68d1eeSLuciano Coelho 			goto out;
14179d68d1eeSLuciano Coelho 		ret = wl1271_cmd_ext_radio_parms(wl);
14189d68d1eeSLuciano Coelho 		if (ret < 0)
14199d68d1eeSLuciano Coelho 			goto out;
14209d68d1eeSLuciano Coelho 	}
14219d68d1eeSLuciano Coelho out:
14229d68d1eeSLuciano Coelho 	return ret;
14239d68d1eeSLuciano Coelho }
14249d68d1eeSLuciano Coelho 
wl12xx_convert_fw_status(struct wl1271 * wl,void * raw_fw_status,struct wl_fw_status * fw_status)142575fb4df7SEliad Peller static void wl12xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
142675fb4df7SEliad Peller 				     struct wl_fw_status *fw_status)
142775fb4df7SEliad Peller {
142875fb4df7SEliad Peller 	struct wl12xx_fw_status *int_fw_status = raw_fw_status;
142975fb4df7SEliad Peller 
143075fb4df7SEliad Peller 	fw_status->intr = le32_to_cpu(int_fw_status->intr);
143175fb4df7SEliad Peller 	fw_status->fw_rx_counter = int_fw_status->fw_rx_counter;
143275fb4df7SEliad Peller 	fw_status->drv_rx_counter = int_fw_status->drv_rx_counter;
143375fb4df7SEliad Peller 	fw_status->tx_results_counter = int_fw_status->tx_results_counter;
143475fb4df7SEliad Peller 	fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs;
143575fb4df7SEliad Peller 
143675fb4df7SEliad Peller 	fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime);
143775fb4df7SEliad Peller 	fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap);
143875fb4df7SEliad Peller 	fw_status->link_fast_bitmap =
143975fb4df7SEliad Peller 			le32_to_cpu(int_fw_status->link_fast_bitmap);
144075fb4df7SEliad Peller 	fw_status->total_released_blks =
144175fb4df7SEliad Peller 			le32_to_cpu(int_fw_status->total_released_blks);
144275fb4df7SEliad Peller 	fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total);
144375fb4df7SEliad Peller 
144475fb4df7SEliad Peller 	fw_status->counters.tx_released_pkts =
144575fb4df7SEliad Peller 			int_fw_status->counters.tx_released_pkts;
144675fb4df7SEliad Peller 	fw_status->counters.tx_lnk_free_pkts =
144775fb4df7SEliad Peller 			int_fw_status->counters.tx_lnk_free_pkts;
144875fb4df7SEliad Peller 	fw_status->counters.tx_voice_released_blks =
144975fb4df7SEliad Peller 			int_fw_status->counters.tx_voice_released_blks;
145075fb4df7SEliad Peller 	fw_status->counters.tx_last_rate =
145175fb4df7SEliad Peller 			int_fw_status->counters.tx_last_rate;
145275fb4df7SEliad Peller 
145375fb4df7SEliad Peller 	fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
145475fb4df7SEliad Peller }
145575fb4df7SEliad Peller 
wl12xx_sta_get_ap_rate_mask(struct wl1271 * wl,struct wl12xx_vif * wlvif)1456fa7930afSArik Nemtsov static u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl,
1457fa7930afSArik Nemtsov 				       struct wl12xx_vif *wlvif)
1458fa7930afSArik Nemtsov {
1459fa7930afSArik Nemtsov 	return wlvif->rate_set;
1460fa7930afSArik Nemtsov }
1461fa7930afSArik Nemtsov 
wl12xx_conf_init(struct wl1271 * wl)1462e87288f0SLuciano Coelho static void wl12xx_conf_init(struct wl1271 *wl)
1463e87288f0SLuciano Coelho {
14645453dc10SLuciano Coelho 	struct wl12xx_priv *priv = wl->priv;
14655453dc10SLuciano Coelho 
1466e87288f0SLuciano Coelho 	/* apply driver default configuration */
1467e87288f0SLuciano Coelho 	memcpy(&wl->conf, &wl12xx_conf, sizeof(wl12xx_conf));
14685453dc10SLuciano Coelho 
14695453dc10SLuciano Coelho 	/* apply default private configuration */
14705453dc10SLuciano Coelho 	memcpy(&priv->conf, &wl12xx_default_priv_conf, sizeof(priv->conf));
1471e87288f0SLuciano Coelho }
1472e87288f0SLuciano Coelho 
wl12xx_mac_in_fuse(struct wl1271 * wl)147330d9b4a5SLuciano Coelho static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
147430d9b4a5SLuciano Coelho {
147530d9b4a5SLuciano Coelho 	bool supported = false;
147630d9b4a5SLuciano Coelho 	u8 major, minor;
147730d9b4a5SLuciano Coelho 
1478986f3aa1SLuciano Coelho 	if (wl->chip.id == CHIP_ID_128X_PG20) {
147930d9b4a5SLuciano Coelho 		major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
148030d9b4a5SLuciano Coelho 		minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
148130d9b4a5SLuciano Coelho 
148230d9b4a5SLuciano Coelho 		/* in wl128x we have the MAC address if the PG is >= (2, 1) */
148330d9b4a5SLuciano Coelho 		if (major > 2 || (major == 2 && minor >= 1))
148430d9b4a5SLuciano Coelho 			supported = true;
148530d9b4a5SLuciano Coelho 	} else {
148630d9b4a5SLuciano Coelho 		major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
148730d9b4a5SLuciano Coelho 		minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
148830d9b4a5SLuciano Coelho 
148930d9b4a5SLuciano Coelho 		/* in wl127x we have the MAC address if the PG is >= (3, 1) */
149030d9b4a5SLuciano Coelho 		if (major == 3 && minor >= 1)
149130d9b4a5SLuciano Coelho 			supported = true;
149230d9b4a5SLuciano Coelho 	}
149330d9b4a5SLuciano Coelho 
149430d9b4a5SLuciano Coelho 	wl1271_debug(DEBUG_PROBE,
149530d9b4a5SLuciano Coelho 		     "PG Ver major = %d minor = %d, MAC %s present",
149630d9b4a5SLuciano Coelho 		     major, minor, supported ? "is" : "is not");
149730d9b4a5SLuciano Coelho 
149830d9b4a5SLuciano Coelho 	return supported;
149930d9b4a5SLuciano Coelho }
150030d9b4a5SLuciano Coelho 
wl12xx_get_fuse_mac(struct wl1271 * wl)15016134323fSIdo Yariv static int wl12xx_get_fuse_mac(struct wl1271 *wl)
150230d9b4a5SLuciano Coelho {
150330d9b4a5SLuciano Coelho 	u32 mac1, mac2;
15046134323fSIdo Yariv 	int ret;
150530d9b4a5SLuciano Coelho 
1506*11ef6bc8STony Lindgren 	/* Device may be in ELP from the bootloader or kexec */
1507*11ef6bc8STony Lindgren 	ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
1508*11ef6bc8STony Lindgren 	if (ret < 0)
1509*11ef6bc8STony Lindgren 		goto out;
1510*11ef6bc8STony Lindgren 
1511*11ef6bc8STony Lindgren 	usleep_range(500000, 700000);
1512*11ef6bc8STony Lindgren 
1513b0f0ad39SIdo Yariv 	ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]);
1514b0f0ad39SIdo Yariv 	if (ret < 0)
1515b0f0ad39SIdo Yariv 		goto out;
151630d9b4a5SLuciano Coelho 
15176134323fSIdo Yariv 	ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1, &mac1);
15186134323fSIdo Yariv 	if (ret < 0)
15196134323fSIdo Yariv 		goto out;
15206134323fSIdo Yariv 
15216134323fSIdo Yariv 	ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2, &mac2);
15226134323fSIdo Yariv 	if (ret < 0)
15236134323fSIdo Yariv 		goto out;
152430d9b4a5SLuciano Coelho 
152530d9b4a5SLuciano Coelho 	/* these are the two parts of the BD_ADDR */
152630d9b4a5SLuciano Coelho 	wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
152730d9b4a5SLuciano Coelho 		((mac1 & 0xff000000) >> 24);
152830d9b4a5SLuciano Coelho 	wl->fuse_nic_addr = mac1 & 0xffffff;
152930d9b4a5SLuciano Coelho 
1530b0f0ad39SIdo Yariv 	ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
15316134323fSIdo Yariv 
15326134323fSIdo Yariv out:
15336134323fSIdo Yariv 	return ret;
153430d9b4a5SLuciano Coelho }
153530d9b4a5SLuciano Coelho 
wl12xx_get_pg_ver(struct wl1271 * wl,s8 * ver)15366134323fSIdo Yariv static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
15374ded91ceSLuciano Coelho {
15386134323fSIdo Yariv 	u16 die_info;
15396134323fSIdo Yariv 	int ret;
15404ded91ceSLuciano Coelho 
1541986f3aa1SLuciano Coelho 	if (wl->chip.id == CHIP_ID_128X_PG20)
15426134323fSIdo Yariv 		ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1,
15436134323fSIdo Yariv 					  &die_info);
15444ded91ceSLuciano Coelho 	else
15456134323fSIdo Yariv 		ret = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1,
15466134323fSIdo Yariv 					  &die_info);
15474ded91ceSLuciano Coelho 
15486134323fSIdo Yariv 	if (ret >= 0 && ver)
15496134323fSIdo Yariv 		*ver = (s8)((die_info & PG_VER_MASK) >> PG_VER_OFFSET);
15506134323fSIdo Yariv 
15516134323fSIdo Yariv 	return ret;
15524ded91ceSLuciano Coelho }
15534ded91ceSLuciano Coelho 
wl12xx_get_mac(struct wl1271 * wl)15546134323fSIdo Yariv static int wl12xx_get_mac(struct wl1271 *wl)
155530d9b4a5SLuciano Coelho {
155630d9b4a5SLuciano Coelho 	if (wl12xx_mac_in_fuse(wl))
15576134323fSIdo Yariv 		return wl12xx_get_fuse_mac(wl);
15586134323fSIdo Yariv 
15596134323fSIdo Yariv 	return 0;
156030d9b4a5SLuciano Coelho }
156130d9b4a5SLuciano Coelho 
wl12xx_set_tx_desc_csum(struct wl1271 * wl,struct wl1271_tx_hw_descr * desc,struct sk_buff * skb)15622fc28de5SArik Nemtsov static void wl12xx_set_tx_desc_csum(struct wl1271 *wl,
15632fc28de5SArik Nemtsov 				    struct wl1271_tx_hw_descr *desc,
15642fc28de5SArik Nemtsov 				    struct sk_buff *skb)
15652fc28de5SArik Nemtsov {
15662fc28de5SArik Nemtsov 	desc->wl12xx_reserved = 0;
15672fc28de5SArik Nemtsov }
15682fc28de5SArik Nemtsov 
wl12xx_plt_init(struct wl1271 * wl)1569c331b344SLuciano Coelho static int wl12xx_plt_init(struct wl1271 *wl)
1570c331b344SLuciano Coelho {
1571c331b344SLuciano Coelho 	int ret;
1572c331b344SLuciano Coelho 
1573c331b344SLuciano Coelho 	ret = wl->ops->boot(wl);
1574c331b344SLuciano Coelho 	if (ret < 0)
1575c331b344SLuciano Coelho 		goto out;
1576c331b344SLuciano Coelho 
1577c331b344SLuciano Coelho 	ret = wl->ops->hw_init(wl);
1578c331b344SLuciano Coelho 	if (ret < 0)
1579c331b344SLuciano Coelho 		goto out_irq_disable;
1580c331b344SLuciano Coelho 
1581ff324317SYair Shapira 	/*
1582ff324317SYair Shapira 	 * If we are in calibrator based auto detect then we got the FEM nr
1583ff324317SYair Shapira 	 * in wl->fem_manuf. No need to continue further
1584ff324317SYair Shapira 	 */
1585ff324317SYair Shapira 	if (wl->plt_mode == PLT_FEM_DETECT)
1586ff324317SYair Shapira 		goto out;
1587ff324317SYair Shapira 
1588c331b344SLuciano Coelho 	ret = wl1271_acx_init_mem_config(wl);
1589c331b344SLuciano Coelho 	if (ret < 0)
1590c331b344SLuciano Coelho 		goto out_irq_disable;
1591c331b344SLuciano Coelho 
1592c331b344SLuciano Coelho 	ret = wl12xx_acx_mem_cfg(wl);
1593c331b344SLuciano Coelho 	if (ret < 0)
1594c331b344SLuciano Coelho 		goto out_free_memmap;
1595c331b344SLuciano Coelho 
1596c331b344SLuciano Coelho 	/* Enable data path */
1597c331b344SLuciano Coelho 	ret = wl1271_cmd_data_path(wl, 1);
1598c331b344SLuciano Coelho 	if (ret < 0)
1599c331b344SLuciano Coelho 		goto out_free_memmap;
1600c331b344SLuciano Coelho 
1601c331b344SLuciano Coelho 	/* Configure for CAM power saving (ie. always active) */
1602c331b344SLuciano Coelho 	ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
1603c331b344SLuciano Coelho 	if (ret < 0)
1604c331b344SLuciano Coelho 		goto out_free_memmap;
1605c331b344SLuciano Coelho 
1606c331b344SLuciano Coelho 	/* configure PM */
1607c331b344SLuciano Coelho 	ret = wl1271_acx_pm_config(wl);
1608c331b344SLuciano Coelho 	if (ret < 0)
1609c331b344SLuciano Coelho 		goto out_free_memmap;
1610c331b344SLuciano Coelho 
1611c331b344SLuciano Coelho 	goto out;
1612c331b344SLuciano Coelho 
1613c331b344SLuciano Coelho out_free_memmap:
1614c331b344SLuciano Coelho 	kfree(wl->target_mem_map);
1615c331b344SLuciano Coelho 	wl->target_mem_map = NULL;
1616c331b344SLuciano Coelho 
1617c331b344SLuciano Coelho out_irq_disable:
1618c331b344SLuciano Coelho 	mutex_unlock(&wl->mutex);
1619c331b344SLuciano Coelho 	/* Unlocking the mutex in the middle of handling is
1620c331b344SLuciano Coelho 	   inherently unsafe. In this case we deem it safe to do,
1621c331b344SLuciano Coelho 	   because we need to let any possibly pending IRQ out of
1622c331b344SLuciano Coelho 	   the system (and while we are WL1271_STATE_OFF the IRQ
1623c331b344SLuciano Coelho 	   work function will not do anything.) Also, any other
1624c331b344SLuciano Coelho 	   possible concurrent operations will fail due to the
1625c331b344SLuciano Coelho 	   current state, hence the wl1271 struct should be safe. */
1626c331b344SLuciano Coelho 	wlcore_disable_interrupts(wl);
1627c331b344SLuciano Coelho 	mutex_lock(&wl->mutex);
1628c331b344SLuciano Coelho out:
1629c331b344SLuciano Coelho 	return ret;
1630c331b344SLuciano Coelho }
1631c331b344SLuciano Coelho 
wl12xx_get_spare_blocks(struct wl1271 * wl,bool is_gem)163232bb2c03SArik Nemtsov static int wl12xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
163332bb2c03SArik Nemtsov {
163432bb2c03SArik Nemtsov 	if (is_gem)
163532bb2c03SArik Nemtsov 		return WL12XX_TX_HW_BLOCK_GEM_SPARE;
163632bb2c03SArik Nemtsov 
163732bb2c03SArik Nemtsov 	return WL12XX_TX_HW_BLOCK_SPARE_DEFAULT;
163832bb2c03SArik Nemtsov }
163932bb2c03SArik Nemtsov 
wl12xx_set_key(struct wl1271 * wl,enum set_key_cmd cmd,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key_conf)1640a1c597f2SArik Nemtsov static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
1641a1c597f2SArik Nemtsov 			  struct ieee80211_vif *vif,
1642a1c597f2SArik Nemtsov 			  struct ieee80211_sta *sta,
1643a1c597f2SArik Nemtsov 			  struct ieee80211_key_conf *key_conf)
1644a1c597f2SArik Nemtsov {
1645a1c597f2SArik Nemtsov 	return wlcore_set_key(wl, cmd, vif, sta, key_conf);
1646a1c597f2SArik Nemtsov }
1647a1c597f2SArik Nemtsov 
wl12xx_set_peer_cap(struct wl1271 * wl,struct ieee80211_sta_ht_cap * ht_cap,bool allow_ht_operation,u32 rate_set,u8 hlid)1648530abe19SEliad Peller static int wl12xx_set_peer_cap(struct wl1271 *wl,
1649530abe19SEliad Peller 			       struct ieee80211_sta_ht_cap *ht_cap,
1650530abe19SEliad Peller 			       bool allow_ht_operation,
1651530abe19SEliad Peller 			       u32 rate_set, u8 hlid)
1652530abe19SEliad Peller {
1653530abe19SEliad Peller 	return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation,
1654530abe19SEliad Peller 					      hlid);
1655530abe19SEliad Peller }
1656530abe19SEliad Peller 
wl12xx_lnk_high_prio(struct wl1271 * wl,u8 hlid,struct wl1271_link * lnk)1657f1626fd8SArik Nemtsov static bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
1658f1626fd8SArik Nemtsov 				 struct wl1271_link *lnk)
1659f1626fd8SArik Nemtsov {
1660f1626fd8SArik Nemtsov 	u8 thold;
1661f1626fd8SArik Nemtsov 
16625e74b3aaSEliad Peller 	if (test_bit(hlid, &wl->fw_fast_lnk_map))
1663f1626fd8SArik Nemtsov 		thold = wl->conf.tx.fast_link_thold;
1664f1626fd8SArik Nemtsov 	else
1665f1626fd8SArik Nemtsov 		thold = wl->conf.tx.slow_link_thold;
1666f1626fd8SArik Nemtsov 
1667f1626fd8SArik Nemtsov 	return lnk->allocated_pkts < thold;
1668f1626fd8SArik Nemtsov }
1669f1626fd8SArik Nemtsov 
wl12xx_lnk_low_prio(struct wl1271 * wl,u8 hlid,struct wl1271_link * lnk)1670f1626fd8SArik Nemtsov static bool wl12xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
1671f1626fd8SArik Nemtsov 				struct wl1271_link *lnk)
1672f1626fd8SArik Nemtsov {
1673f1626fd8SArik Nemtsov 	/* any link is good for low priority */
1674f1626fd8SArik Nemtsov 	return true;
1675f1626fd8SArik Nemtsov }
1676f1626fd8SArik Nemtsov 
wl12xx_convert_hwaddr(struct wl1271 * wl,u32 hwaddr)1677c83cb803SIgal Chernobelsky static u32 wl12xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
1678c83cb803SIgal Chernobelsky {
1679c83cb803SIgal Chernobelsky 	return hwaddr << 5;
1680c83cb803SIgal Chernobelsky }
1681c83cb803SIgal Chernobelsky 
16823992eb2bSIdo Yariv static int wl12xx_setup(struct wl1271 *wl);
16833992eb2bSIdo Yariv 
16846f7dd16cSLuciano Coelho static struct wlcore_ops wl12xx_ops = {
16853992eb2bSIdo Yariv 	.setup			= wl12xx_setup,
16866f7dd16cSLuciano Coelho 	.identify_chip		= wl12xx_identify_chip,
1687dd5512ebSLuciano Coelho 	.boot			= wl12xx_boot,
1688c331b344SLuciano Coelho 	.plt_init		= wl12xx_plt_init,
1689f16ff758SLuciano Coelho 	.trigger_cmd		= wl12xx_trigger_cmd,
1690f16ff758SLuciano Coelho 	.ack_event		= wl12xx_ack_event,
1691c50a2825SEliad Peller 	.wait_for_event		= wl12xx_wait_for_event,
1692c50a2825SEliad Peller 	.process_mailbox_events	= wl12xx_process_mailbox_events,
1693b3b4b4b8SArik Nemtsov 	.calc_tx_blocks		= wl12xx_calc_tx_blocks,
16944a3b97eeSArik Nemtsov 	.set_tx_desc_blocks	= wl12xx_set_tx_desc_blocks,
16956f266e91SArik Nemtsov 	.set_tx_desc_data_len	= wl12xx_set_tx_desc_data_len,
1696cd70f6a4SArik Nemtsov 	.get_rx_buf_align	= wl12xx_get_rx_buf_align,
16974158149cSArik Nemtsov 	.get_rx_packet_len	= wl12xx_get_rx_packet_len,
169853d67a50SArik Nemtsov 	.tx_immediate_compl	= NULL,
169953d67a50SArik Nemtsov 	.tx_delayed_compl	= wl12xx_tx_delayed_compl,
17009d68d1eeSLuciano Coelho 	.hw_init		= wl12xx_hw_init,
17018a9affc0SArik Nemtsov 	.init_vif		= NULL,
170275fb4df7SEliad Peller 	.convert_fw_status	= wl12xx_convert_fw_status,
1703fa7930afSArik Nemtsov 	.sta_get_ap_rate_mask	= wl12xx_sta_get_ap_rate_mask,
17044ded91ceSLuciano Coelho 	.get_pg_ver		= wl12xx_get_pg_ver,
170530d9b4a5SLuciano Coelho 	.get_mac		= wl12xx_get_mac,
17062fc28de5SArik Nemtsov 	.set_tx_desc_csum	= wl12xx_set_tx_desc_csum,
1707169da04fSArik Nemtsov 	.set_rx_csum		= NULL,
1708ebc7e57dSArik Nemtsov 	.ap_get_mimo_wide_rate_mask = NULL,
1709ad62d81aSLuciano Coelho 	.debugfs_init		= wl12xx_debugfs_add_files,
171078e28062SEliad Peller 	.scan_start		= wl12xx_scan_start,
171178e28062SEliad Peller 	.scan_stop		= wl12xx_scan_stop,
171278e28062SEliad Peller 	.sched_scan_start	= wl12xx_sched_scan_start,
171378e28062SEliad Peller 	.sched_scan_stop	= wl12xx_scan_sched_scan_stop,
171432bb2c03SArik Nemtsov 	.get_spare_blocks	= wl12xx_get_spare_blocks,
1715a1c597f2SArik Nemtsov 	.set_key		= wl12xx_set_key,
1716fcab1890SEliad Peller 	.channel_switch		= wl12xx_cmd_channel_switch,
17179fccc82eSIdo Reis 	.pre_pkt_send		= NULL,
1718530abe19SEliad Peller 	.set_peer_cap		= wl12xx_set_peer_cap,
1719c83cb803SIgal Chernobelsky 	.convert_hwaddr		= wl12xx_convert_hwaddr,
1720f1626fd8SArik Nemtsov 	.lnk_high_prio		= wl12xx_lnk_high_prio,
1721f1626fd8SArik Nemtsov 	.lnk_low_prio		= wl12xx_lnk_low_prio,
17226d5a748dSRam Amrani 	.interrupt_notify	= NULL,
17236d5a748dSRam Amrani 	.rx_ba_filter		= NULL,
1724e2f1e50fSKobi L 	.ap_sleep		= NULL,
17256f7dd16cSLuciano Coelho };
17266f7dd16cSLuciano Coelho 
17274a589a6fSArik Nemtsov static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
17284a589a6fSArik Nemtsov 	.cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
17294a589a6fSArik Nemtsov 	       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT),
17304a589a6fSArik Nemtsov 	.ht_supported = true,
17314a589a6fSArik Nemtsov 	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K,
17324a589a6fSArik Nemtsov 	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8,
17334a589a6fSArik Nemtsov 	.mcs = {
17344a589a6fSArik Nemtsov 		.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
17354a589a6fSArik Nemtsov 		.rx_highest = cpu_to_le16(72),
17364a589a6fSArik Nemtsov 		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
17374a589a6fSArik Nemtsov 		},
17384a589a6fSArik Nemtsov };
17394a589a6fSArik Nemtsov 
1740abf0b249SEliad Peller static const struct ieee80211_iface_limit wl12xx_iface_limits[] = {
1741abf0b249SEliad Peller 	{
1742abf0b249SEliad Peller 		.max = 3,
1743abf0b249SEliad Peller 		.types = BIT(NL80211_IFTYPE_STATION),
1744abf0b249SEliad Peller 	},
1745abf0b249SEliad Peller 	{
1746abf0b249SEliad Peller 		.max = 1,
1747abf0b249SEliad Peller 		.types = BIT(NL80211_IFTYPE_AP) |
1748abf0b249SEliad Peller 			 BIT(NL80211_IFTYPE_P2P_GO) |
1749abf0b249SEliad Peller 			 BIT(NL80211_IFTYPE_P2P_CLIENT),
1750abf0b249SEliad Peller 	},
1751abf0b249SEliad Peller };
1752abf0b249SEliad Peller 
1753abf0b249SEliad Peller static const struct ieee80211_iface_combination
1754abf0b249SEliad Peller wl12xx_iface_combinations[] = {
1755abf0b249SEliad Peller 	{
1756abf0b249SEliad Peller 		.max_interfaces = 3,
1757abf0b249SEliad Peller 		.limits = wl12xx_iface_limits,
1758abf0b249SEliad Peller 		.n_limits = ARRAY_SIZE(wl12xx_iface_limits),
1759abf0b249SEliad Peller 		.num_different_channels = 1,
1760abf0b249SEliad Peller 	},
1761abf0b249SEliad Peller };
1762abf0b249SEliad Peller 
176344486b48SLuciano Coelho static const struct wl12xx_clock wl12xx_refclock_table[] = {
176444486b48SLuciano Coelho 	{ 19200000,	false,	WL12XX_REFCLOCK_19	},
176544486b48SLuciano Coelho 	{ 26000000,	false,	WL12XX_REFCLOCK_26	},
176644486b48SLuciano Coelho 	{ 26000000,	true,	WL12XX_REFCLOCK_26_XTAL	},
176744486b48SLuciano Coelho 	{ 38400000,	false,	WL12XX_REFCLOCK_38	},
176844486b48SLuciano Coelho 	{ 38400000,	true,	WL12XX_REFCLOCK_38_XTAL	},
176944486b48SLuciano Coelho 	{ 52000000,	false,	WL12XX_REFCLOCK_52	},
177044486b48SLuciano Coelho 	{ 0,		false,	0 }
177144486b48SLuciano Coelho };
177244486b48SLuciano Coelho 
177344486b48SLuciano Coelho static const struct wl12xx_clock wl12xx_tcxoclock_table[] = {
177444486b48SLuciano Coelho 	{ 16368000,	true,	WL12XX_TCXOCLOCK_16_368	},
177544486b48SLuciano Coelho 	{ 16800000,	true,	WL12XX_TCXOCLOCK_16_8	},
177644486b48SLuciano Coelho 	{ 19200000,	true,	WL12XX_TCXOCLOCK_19_2	},
177744486b48SLuciano Coelho 	{ 26000000,	true,	WL12XX_TCXOCLOCK_26	},
177844486b48SLuciano Coelho 	{ 32736000,	true,	WL12XX_TCXOCLOCK_32_736	},
177944486b48SLuciano Coelho 	{ 33600000,	true,	WL12XX_TCXOCLOCK_33_6	},
178044486b48SLuciano Coelho 	{ 38400000,	true,	WL12XX_TCXOCLOCK_38_4	},
178144486b48SLuciano Coelho 	{ 52000000,	true,	WL12XX_TCXOCLOCK_52	},
178244486b48SLuciano Coelho 	{ 0,		false,	0 }
178344486b48SLuciano Coelho };
178444486b48SLuciano Coelho 
wl12xx_get_clock_idx(const struct wl12xx_clock * table,u32 freq,bool xtal)178544486b48SLuciano Coelho static int wl12xx_get_clock_idx(const struct wl12xx_clock *table,
178644486b48SLuciano Coelho 				u32 freq, bool xtal)
178744486b48SLuciano Coelho {
178844486b48SLuciano Coelho 	int i;
178944486b48SLuciano Coelho 
179044486b48SLuciano Coelho 	for (i = 0; table[i].freq != 0; i++)
179144486b48SLuciano Coelho 		if ((table[i].freq == freq) && (table[i].xtal == xtal))
179244486b48SLuciano Coelho 			return table[i].hw_idx;
179344486b48SLuciano Coelho 
179444486b48SLuciano Coelho 	return -EINVAL;
179544486b48SLuciano Coelho }
179644486b48SLuciano Coelho 
wl12xx_setup(struct wl1271 * wl)17973992eb2bSIdo Yariv static int wl12xx_setup(struct wl1271 *wl)
1798ffeb501cSLuciano Coelho {
17993992eb2bSIdo Yariv 	struct wl12xx_priv *priv = wl->priv;
1800c4978e25SJingoo Han 	struct wlcore_platdev_data *pdev_data = dev_get_platdata(&wl->pdev->dev);
1801ffeb501cSLuciano Coelho 
1802da08fdfaSEliad Peller 	BUILD_BUG_ON(WL12XX_MAX_LINKS > WLCORE_MAX_LINKS);
180332f0fd5bSEliad Peller 	BUILD_BUG_ON(WL12XX_MAX_AP_STATIONS > WL12XX_MAX_LINKS);
1804133b7326SGuy Mishol 	BUILD_BUG_ON(WL12XX_CONF_SG_PARAMS_MAX > WLCORE_CONF_SG_PARAMS_MAX);
1805da08fdfaSEliad Peller 
180600782136SLuciano Coelho 	wl->rtable = wl12xx_rtable;
1807f1c434dfSIgal Chernobelsky 	wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS;
1808f1c434dfSIgal Chernobelsky 	wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS;
1809da08fdfaSEliad Peller 	wl->num_links = WL12XX_MAX_LINKS;
181032f0fd5bSEliad Peller 	wl->max_ap_stations = WL12XX_MAX_AP_STATIONS;
1811abf0b249SEliad Peller 	wl->iface_combinations = wl12xx_iface_combinations;
1812abf0b249SEliad Peller 	wl->n_iface_combinations = ARRAY_SIZE(wl12xx_iface_combinations);
1813f4afbed9SArik Nemtsov 	wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES;
181443a8bc5aSArik Nemtsov 	wl->band_rate_to_idx = wl12xx_band_rate_to_idx;
181543a8bc5aSArik Nemtsov 	wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX;
181643a8bc5aSArik Nemtsov 	wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0;
181775fb4df7SEliad Peller 	wl->fw_status_len = sizeof(struct wl12xx_fw_status);
18186bac40a6SArik Nemtsov 	wl->fw_status_priv_len = 0;
181910b1e8a2SLuciano Coelho 	wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics);
1820bc566f92SArik Nemtsov 	wl->ofdm_only_ap = true;
182157fbcce3SJohannes Berg 	wlcore_set_ht_cap(wl, NL80211_BAND_2GHZ, &wl12xx_ht_cap);
182257fbcce3SJohannes Berg 	wlcore_set_ht_cap(wl, NL80211_BAND_5GHZ, &wl12xx_ht_cap);
1823e87288f0SLuciano Coelho 	wl12xx_conf_init(wl);
1824ffeb501cSLuciano Coelho 
1825a5d751bbSLuciano Coelho 	if (!fref_param) {
182644486b48SLuciano Coelho 		priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table,
182783c3a7d4SEliad Peller 						pdev_data->ref_clock_freq,
182883c3a7d4SEliad Peller 						pdev_data->ref_clock_xtal);
182944486b48SLuciano Coelho 		if (priv->ref_clock < 0) {
183044486b48SLuciano Coelho 			wl1271_error("Invalid ref_clock frequency (%d Hz, %s)",
183183c3a7d4SEliad Peller 				     pdev_data->ref_clock_freq,
183283c3a7d4SEliad Peller 				     pdev_data->ref_clock_xtal ?
183344486b48SLuciano Coelho 				     "XTAL" : "not XTAL");
183444486b48SLuciano Coelho 
183544486b48SLuciano Coelho 			return priv->ref_clock;
183644486b48SLuciano Coelho 		}
1837a5d751bbSLuciano Coelho 	} else {
1838a5d751bbSLuciano Coelho 		if (!strcmp(fref_param, "19.2"))
1839a5d751bbSLuciano Coelho 			priv->ref_clock = WL12XX_REFCLOCK_19;
1840a5d751bbSLuciano Coelho 		else if (!strcmp(fref_param, "26"))
1841a5d751bbSLuciano Coelho 			priv->ref_clock = WL12XX_REFCLOCK_26;
1842a5d751bbSLuciano Coelho 		else if (!strcmp(fref_param, "26x"))
1843a5d751bbSLuciano Coelho 			priv->ref_clock = WL12XX_REFCLOCK_26_XTAL;
1844a5d751bbSLuciano Coelho 		else if (!strcmp(fref_param, "38.4"))
1845a5d751bbSLuciano Coelho 			priv->ref_clock = WL12XX_REFCLOCK_38;
1846a5d751bbSLuciano Coelho 		else if (!strcmp(fref_param, "38.4x"))
1847a5d751bbSLuciano Coelho 			priv->ref_clock = WL12XX_REFCLOCK_38_XTAL;
1848a5d751bbSLuciano Coelho 		else if (!strcmp(fref_param, "52"))
1849a5d751bbSLuciano Coelho 			priv->ref_clock = WL12XX_REFCLOCK_52;
1850a5d751bbSLuciano Coelho 		else
1851a5d751bbSLuciano Coelho 			wl1271_error("Invalid fref parameter %s", fref_param);
1852a5d751bbSLuciano Coelho 	}
1853a5d751bbSLuciano Coelho 
185483c3a7d4SEliad Peller 	if (!tcxo_param && pdev_data->tcxo_clock_freq) {
185544486b48SLuciano Coelho 		priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table,
185683c3a7d4SEliad Peller 						pdev_data->tcxo_clock_freq,
185744486b48SLuciano Coelho 						true);
185844486b48SLuciano Coelho 		if (priv->tcxo_clock < 0) {
185944486b48SLuciano Coelho 			wl1271_error("Invalid tcxo_clock frequency (%d Hz)",
186083c3a7d4SEliad Peller 				     pdev_data->tcxo_clock_freq);
186144486b48SLuciano Coelho 
186244486b48SLuciano Coelho 			return priv->tcxo_clock;
186344486b48SLuciano Coelho 		}
186444486b48SLuciano Coelho 	} else if (tcxo_param) {
1865a5d751bbSLuciano Coelho 		if (!strcmp(tcxo_param, "19.2"))
1866a5d751bbSLuciano Coelho 			priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2;
1867a5d751bbSLuciano Coelho 		else if (!strcmp(tcxo_param, "26"))
1868a5d751bbSLuciano Coelho 			priv->tcxo_clock = WL12XX_TCXOCLOCK_26;
1869a5d751bbSLuciano Coelho 		else if (!strcmp(tcxo_param, "38.4"))
1870a5d751bbSLuciano Coelho 			priv->tcxo_clock = WL12XX_TCXOCLOCK_38_4;
1871a5d751bbSLuciano Coelho 		else if (!strcmp(tcxo_param, "52"))
1872a5d751bbSLuciano Coelho 			priv->tcxo_clock = WL12XX_TCXOCLOCK_52;
1873a5d751bbSLuciano Coelho 		else if (!strcmp(tcxo_param, "16.368"))
1874a5d751bbSLuciano Coelho 			priv->tcxo_clock = WL12XX_TCXOCLOCK_16_368;
1875a5d751bbSLuciano Coelho 		else if (!strcmp(tcxo_param, "32.736"))
1876a5d751bbSLuciano Coelho 			priv->tcxo_clock = WL12XX_TCXOCLOCK_32_736;
1877a5d751bbSLuciano Coelho 		else if (!strcmp(tcxo_param, "16.8"))
1878a5d751bbSLuciano Coelho 			priv->tcxo_clock = WL12XX_TCXOCLOCK_16_8;
1879a5d751bbSLuciano Coelho 		else if (!strcmp(tcxo_param, "33.6"))
1880a5d751bbSLuciano Coelho 			priv->tcxo_clock = WL12XX_TCXOCLOCK_33_6;
1881a5d751bbSLuciano Coelho 		else
1882a5d751bbSLuciano Coelho 			wl1271_error("Invalid tcxo parameter %s", tcxo_param);
1883a5d751bbSLuciano Coelho 	}
1884a5d751bbSLuciano Coelho 
18852e07d028SIdo Yariv 	priv->rx_mem_addr = kmalloc(sizeof(*priv->rx_mem_addr), GFP_KERNEL);
18862e07d028SIdo Yariv 	if (!priv->rx_mem_addr)
18872e07d028SIdo Yariv 		return -ENOMEM;
18882e07d028SIdo Yariv 
18893992eb2bSIdo Yariv 	return 0;
18903992eb2bSIdo Yariv }
18913992eb2bSIdo Yariv 
wl12xx_probe(struct platform_device * pdev)1892b74324d1SBill Pemberton static int wl12xx_probe(struct platform_device *pdev)
18933992eb2bSIdo Yariv {
18943992eb2bSIdo Yariv 	struct wl1271 *wl;
18953992eb2bSIdo Yariv 	struct ieee80211_hw *hw;
18963992eb2bSIdo Yariv 	int ret;
18973992eb2bSIdo Yariv 
18983992eb2bSIdo Yariv 	hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv),
1899c50a2825SEliad Peller 			     WL12XX_AGGR_BUFFER_SIZE,
1900c50a2825SEliad Peller 			     sizeof(struct wl12xx_event_mailbox));
19013992eb2bSIdo Yariv 	if (IS_ERR(hw)) {
19023992eb2bSIdo Yariv 		wl1271_error("can't allocate hw");
19033992eb2bSIdo Yariv 		ret = PTR_ERR(hw);
19043992eb2bSIdo Yariv 		goto out;
19053992eb2bSIdo Yariv 	}
19063992eb2bSIdo Yariv 
19073992eb2bSIdo Yariv 	wl = hw->priv;
19083992eb2bSIdo Yariv 	wl->ops = &wl12xx_ops;
19093992eb2bSIdo Yariv 	wl->ptable = wl12xx_ptable;
19103992eb2bSIdo Yariv 	ret = wlcore_probe(wl, pdev);
19113992eb2bSIdo Yariv 	if (ret)
19123992eb2bSIdo Yariv 		goto out_free;
19133992eb2bSIdo Yariv 
19143992eb2bSIdo Yariv 	return ret;
19153992eb2bSIdo Yariv 
19163992eb2bSIdo Yariv out_free:
19173992eb2bSIdo Yariv 	wlcore_free_hw(wl);
19183992eb2bSIdo Yariv out:
19193992eb2bSIdo Yariv 	return ret;
1920ffeb501cSLuciano Coelho }
1921b2ba99ffSLuciano Coelho 
wl12xx_remove(struct platform_device * pdev)19225b37649bSLuciano Coelho static int wl12xx_remove(struct platform_device *pdev)
19232e07d028SIdo Yariv {
19242e07d028SIdo Yariv 	struct wl1271 *wl = platform_get_drvdata(pdev);
19252e07d028SIdo Yariv 	struct wl12xx_priv *priv;
19262e07d028SIdo Yariv 
19272e07d028SIdo Yariv 	priv = wl->priv;
19282e07d028SIdo Yariv 
19292e07d028SIdo Yariv 	kfree(priv->rx_mem_addr);
19302e07d028SIdo Yariv 
19312e07d028SIdo Yariv 	return wlcore_remove(pdev);
19322e07d028SIdo Yariv }
19332e07d028SIdo Yariv 
1934b74324d1SBill Pemberton static const struct platform_device_id wl12xx_id_table[] = {
1935b2ba99ffSLuciano Coelho 	{ "wl12xx", 0 },
1936b2ba99ffSLuciano Coelho 	{  } /* Terminating Entry */
1937b2ba99ffSLuciano Coelho };
1938b2ba99ffSLuciano Coelho MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
1939b2ba99ffSLuciano Coelho 
1940b2ba99ffSLuciano Coelho static struct platform_driver wl12xx_driver = {
1941ffeb501cSLuciano Coelho 	.probe		= wl12xx_probe,
19425b37649bSLuciano Coelho 	.remove		= wl12xx_remove,
1943b2ba99ffSLuciano Coelho 	.id_table	= wl12xx_id_table,
1944b2ba99ffSLuciano Coelho 	.driver = {
1945b2ba99ffSLuciano Coelho 		.name	= "wl12xx_driver",
1946b2ba99ffSLuciano Coelho 	}
1947b2ba99ffSLuciano Coelho };
1948b2ba99ffSLuciano Coelho 
1949ae35c30cSLuciano Coelho module_platform_driver(wl12xx_driver);
1950b2ba99ffSLuciano Coelho 
1951a5d751bbSLuciano Coelho module_param_named(fref, fref_param, charp, 0);
1952a5d751bbSLuciano Coelho MODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52");
1953a5d751bbSLuciano Coelho 
1954a5d751bbSLuciano Coelho module_param_named(tcxo, tcxo_param, charp, 0);
1955a5d751bbSLuciano Coelho MODULE_PARM_DESC(tcxo,
1956a5d751bbSLuciano Coelho 		 "TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6");
1957a5d751bbSLuciano Coelho 
1958b2ba99ffSLuciano Coelho MODULE_LICENSE("GPL v2");
1959b2ba99ffSLuciano Coelho MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
19606f7dd16cSLuciano Coelho MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
19616f7dd16cSLuciano Coelho MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
19626f7dd16cSLuciano Coelho MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
19636f7dd16cSLuciano Coelho MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
19646f7dd16cSLuciano Coelho MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
19656f7dd16cSLuciano Coelho MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
1966