162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is part of wl18xx
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci#include <linux/ip.h>
1262306a36Sopenharmony_ci#include <linux/firmware.h>
1362306a36Sopenharmony_ci#include <linux/etherdevice.h>
1462306a36Sopenharmony_ci#include <linux/irq.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "../wlcore/wlcore.h"
1762306a36Sopenharmony_ci#include "../wlcore/debug.h"
1862306a36Sopenharmony_ci#include "../wlcore/io.h"
1962306a36Sopenharmony_ci#include "../wlcore/acx.h"
2062306a36Sopenharmony_ci#include "../wlcore/tx.h"
2162306a36Sopenharmony_ci#include "../wlcore/rx.h"
2262306a36Sopenharmony_ci#include "../wlcore/boot.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "reg.h"
2562306a36Sopenharmony_ci#include "conf.h"
2662306a36Sopenharmony_ci#include "cmd.h"
2762306a36Sopenharmony_ci#include "acx.h"
2862306a36Sopenharmony_ci#include "tx.h"
2962306a36Sopenharmony_ci#include "wl18xx.h"
3062306a36Sopenharmony_ci#include "io.h"
3162306a36Sopenharmony_ci#include "scan.h"
3262306a36Sopenharmony_ci#include "event.h"
3362306a36Sopenharmony_ci#include "debugfs.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define WL18XX_RX_CHECKSUM_MASK      0x40
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic char *ht_mode_param = NULL;
3862306a36Sopenharmony_cistatic char *board_type_param = NULL;
3962306a36Sopenharmony_cistatic bool checksum_param = false;
4062306a36Sopenharmony_cistatic int num_rx_desc_param = -1;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* phy paramters */
4362306a36Sopenharmony_cistatic int dc2dc_param = -1;
4462306a36Sopenharmony_cistatic int n_antennas_2_param = -1;
4562306a36Sopenharmony_cistatic int n_antennas_5_param = -1;
4662306a36Sopenharmony_cistatic int low_band_component_param = -1;
4762306a36Sopenharmony_cistatic int low_band_component_type_param = -1;
4862306a36Sopenharmony_cistatic int high_band_component_param = -1;
4962306a36Sopenharmony_cistatic int high_band_component_type_param = -1;
5062306a36Sopenharmony_cistatic int pwr_limit_reference_11_abg_param = -1;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic const u8 wl18xx_rate_to_idx_2ghz[] = {
5362306a36Sopenharmony_ci	/* MCS rates are used only with 11n */
5462306a36Sopenharmony_ci	15,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
5562306a36Sopenharmony_ci	14,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
5662306a36Sopenharmony_ci	13,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
5762306a36Sopenharmony_ci	12,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
5862306a36Sopenharmony_ci	11,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
5962306a36Sopenharmony_ci	10,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
6062306a36Sopenharmony_ci	9,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
6162306a36Sopenharmony_ci	8,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
6262306a36Sopenharmony_ci	7,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
6362306a36Sopenharmony_ci	6,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
6462306a36Sopenharmony_ci	5,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
6562306a36Sopenharmony_ci	4,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
6662306a36Sopenharmony_ci	3,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
6762306a36Sopenharmony_ci	2,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
6862306a36Sopenharmony_ci	1,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
6962306a36Sopenharmony_ci	0,                             /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	11,                            /* WL18XX_CONF_HW_RXTX_RATE_54   */
7262306a36Sopenharmony_ci	10,                            /* WL18XX_CONF_HW_RXTX_RATE_48   */
7362306a36Sopenharmony_ci	9,                             /* WL18XX_CONF_HW_RXTX_RATE_36   */
7462306a36Sopenharmony_ci	8,                             /* WL18XX_CONF_HW_RXTX_RATE_24   */
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/* TI-specific rate */
7762306a36Sopenharmony_ci	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22   */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	7,                             /* WL18XX_CONF_HW_RXTX_RATE_18   */
8062306a36Sopenharmony_ci	6,                             /* WL18XX_CONF_HW_RXTX_RATE_12   */
8162306a36Sopenharmony_ci	3,                             /* WL18XX_CONF_HW_RXTX_RATE_11   */
8262306a36Sopenharmony_ci	5,                             /* WL18XX_CONF_HW_RXTX_RATE_9    */
8362306a36Sopenharmony_ci	4,                             /* WL18XX_CONF_HW_RXTX_RATE_6    */
8462306a36Sopenharmony_ci	2,                             /* WL18XX_CONF_HW_RXTX_RATE_5_5  */
8562306a36Sopenharmony_ci	1,                             /* WL18XX_CONF_HW_RXTX_RATE_2    */
8662306a36Sopenharmony_ci	0                              /* WL18XX_CONF_HW_RXTX_RATE_1    */
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic const u8 wl18xx_rate_to_idx_5ghz[] = {
9062306a36Sopenharmony_ci	/* MCS rates are used only with 11n */
9162306a36Sopenharmony_ci	15,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS15 */
9262306a36Sopenharmony_ci	14,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS14 */
9362306a36Sopenharmony_ci	13,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS13 */
9462306a36Sopenharmony_ci	12,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS12 */
9562306a36Sopenharmony_ci	11,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS11 */
9662306a36Sopenharmony_ci	10,                           /* WL18XX_CONF_HW_RXTX_RATE_MCS10 */
9762306a36Sopenharmony_ci	9,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS9 */
9862306a36Sopenharmony_ci	8,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS8 */
9962306a36Sopenharmony_ci	7,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS7 */
10062306a36Sopenharmony_ci	6,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS6 */
10162306a36Sopenharmony_ci	5,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS5 */
10262306a36Sopenharmony_ci	4,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS4 */
10362306a36Sopenharmony_ci	3,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS3 */
10462306a36Sopenharmony_ci	2,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS2 */
10562306a36Sopenharmony_ci	1,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS1 */
10662306a36Sopenharmony_ci	0,                            /* WL18XX_CONF_HW_RXTX_RATE_MCS0 */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	7,                             /* WL18XX_CONF_HW_RXTX_RATE_54   */
10962306a36Sopenharmony_ci	6,                             /* WL18XX_CONF_HW_RXTX_RATE_48   */
11062306a36Sopenharmony_ci	5,                             /* WL18XX_CONF_HW_RXTX_RATE_36   */
11162306a36Sopenharmony_ci	4,                             /* WL18XX_CONF_HW_RXTX_RATE_24   */
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* TI-specific rate */
11462306a36Sopenharmony_ci	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_22   */
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	3,                             /* WL18XX_CONF_HW_RXTX_RATE_18   */
11762306a36Sopenharmony_ci	2,                             /* WL18XX_CONF_HW_RXTX_RATE_12   */
11862306a36Sopenharmony_ci	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_11   */
11962306a36Sopenharmony_ci	1,                             /* WL18XX_CONF_HW_RXTX_RATE_9    */
12062306a36Sopenharmony_ci	0,                             /* WL18XX_CONF_HW_RXTX_RATE_6    */
12162306a36Sopenharmony_ci	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_5_5  */
12262306a36Sopenharmony_ci	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_2    */
12362306a36Sopenharmony_ci	CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL18XX_CONF_HW_RXTX_RATE_1    */
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic const u8 *wl18xx_band_rate_to_idx[] = {
12762306a36Sopenharmony_ci	[NL80211_BAND_2GHZ] = wl18xx_rate_to_idx_2ghz,
12862306a36Sopenharmony_ci	[NL80211_BAND_5GHZ] = wl18xx_rate_to_idx_5ghz
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cienum wl18xx_hw_rates {
13262306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS15 = 0,
13362306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS14,
13462306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS13,
13562306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS12,
13662306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS11,
13762306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS10,
13862306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS9,
13962306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS8,
14062306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS7,
14162306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS6,
14262306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS5,
14362306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS4,
14462306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS3,
14562306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS2,
14662306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS1,
14762306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MCS0,
14862306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_54,
14962306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_48,
15062306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_36,
15162306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_24,
15262306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_22,
15362306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_18,
15462306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_12,
15562306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_11,
15662306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_9,
15762306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_6,
15862306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_5_5,
15962306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_2,
16062306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_1,
16162306a36Sopenharmony_ci	WL18XX_CONF_HW_RXTX_RATE_MAX,
16262306a36Sopenharmony_ci};
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic struct wlcore_conf wl18xx_conf = {
16562306a36Sopenharmony_ci	.sg = {
16662306a36Sopenharmony_ci		.params = {
16762306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_0] = 0,
16862306a36Sopenharmony_ci			/* Configuration Parameters */
16962306a36Sopenharmony_ci			[WL18XX_CONF_SG_ANTENNA_CONFIGURATION] = 0,
17062306a36Sopenharmony_ci			[WL18XX_CONF_SG_ZIGBEE_COEX] = 0,
17162306a36Sopenharmony_ci			[WL18XX_CONF_SG_TIME_SYNC] = 0,
17262306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_4] = 0,
17362306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_5] = 0,
17462306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_6] = 0,
17562306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_7] = 0,
17662306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_8] = 0,
17762306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_9] = 0,
17862306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_10] = 0,
17962306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_11] = 0,
18062306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_12] = 0,
18162306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_13] = 0,
18262306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_14] = 0,
18362306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_15] = 0,
18462306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_16] = 0,
18562306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_17] = 0,
18662306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_18] = 0,
18762306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_19] = 0,
18862306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_20] = 0,
18962306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_21] = 0,
19062306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_22] = 0,
19162306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_23] = 0,
19262306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_24] = 0,
19362306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_25] = 0,
19462306a36Sopenharmony_ci			/* Active Scan Parameters */
19562306a36Sopenharmony_ci			[WL18XX_CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
19662306a36Sopenharmony_ci			[WL18XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
19762306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_28] = 0,
19862306a36Sopenharmony_ci			/* Passive Scan Parameters */
19962306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_29] = 0,
20062306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_30] = 0,
20162306a36Sopenharmony_ci			[WL18XX_CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
20262306a36Sopenharmony_ci			/* Passive Scan in Dual Antenna Parameters */
20362306a36Sopenharmony_ci			[WL18XX_CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
20462306a36Sopenharmony_ci			[WL18XX_CONF_SG_BEACON_HV3_COLL_TH_IN_PASSIVE_SCAN] = 0,
20562306a36Sopenharmony_ci			[WL18XX_CONF_SG_TX_RX_PROTECT_BW_IN_PASSIVE_SCAN] = 0,
20662306a36Sopenharmony_ci			/* General Parameters */
20762306a36Sopenharmony_ci			[WL18XX_CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
20862306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_36] = 0,
20962306a36Sopenharmony_ci			[WL18XX_CONF_SG_BEACON_MISS_PERCENT] = 60,
21062306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_38] = 0,
21162306a36Sopenharmony_ci			[WL18XX_CONF_SG_RXT] = 1200,
21262306a36Sopenharmony_ci			[WL18XX_CONF_SG_UNUSED] = 0,
21362306a36Sopenharmony_ci			[WL18XX_CONF_SG_ADAPTIVE_RXT_TXT] = 1,
21462306a36Sopenharmony_ci			[WL18XX_CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
21562306a36Sopenharmony_ci			[WL18XX_CONF_SG_HV3_MAX_SERVED] = 6,
21662306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_44] = 0,
21762306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_45] = 0,
21862306a36Sopenharmony_ci			[WL18XX_CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
21962306a36Sopenharmony_ci			[WL18XX_CONF_SG_GEMINI_PARAM_47] = 0,
22062306a36Sopenharmony_ci			[WL18XX_CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 0,
22162306a36Sopenharmony_ci			/* AP Parameters */
22262306a36Sopenharmony_ci			[WL18XX_CONF_SG_AP_BEACON_MISS_TX] = 3,
22362306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_50] = 0,
22462306a36Sopenharmony_ci			[WL18XX_CONF_SG_AP_BEACON_WINDOW_INTERVAL] = 2,
22562306a36Sopenharmony_ci			[WL18XX_CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 30,
22662306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_53] = 0,
22762306a36Sopenharmony_ci			[WL18XX_CONF_SG_PARAM_54] = 0,
22862306a36Sopenharmony_ci			/* CTS Diluting Parameters */
22962306a36Sopenharmony_ci			[WL18XX_CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
23062306a36Sopenharmony_ci			[WL18XX_CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
23162306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_1] = 0,
23262306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_2] = 0,
23362306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_3] = 0,
23462306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_4] = 0,
23562306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_5] = 0,
23662306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_6] = 0,
23762306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_7] = 0,
23862306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_8] = 0,
23962306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_9] = 0,
24062306a36Sopenharmony_ci			[WL18XX_CONF_SG_TEMP_PARAM_10] = 0,
24162306a36Sopenharmony_ci		},
24262306a36Sopenharmony_ci		.state = CONF_SG_PROTECTIVE,
24362306a36Sopenharmony_ci	},
24462306a36Sopenharmony_ci	.rx = {
24562306a36Sopenharmony_ci		.rx_msdu_life_time           = 512000,
24662306a36Sopenharmony_ci		.packet_detection_threshold  = 0,
24762306a36Sopenharmony_ci		.ps_poll_timeout             = 15,
24862306a36Sopenharmony_ci		.upsd_timeout                = 15,
24962306a36Sopenharmony_ci		.rts_threshold               = IEEE80211_MAX_RTS_THRESHOLD,
25062306a36Sopenharmony_ci		.rx_cca_threshold            = 0,
25162306a36Sopenharmony_ci		.irq_blk_threshold           = 0xFFFF,
25262306a36Sopenharmony_ci		.irq_pkt_threshold           = 0,
25362306a36Sopenharmony_ci		.irq_timeout                 = 600,
25462306a36Sopenharmony_ci		.queue_type                  = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
25562306a36Sopenharmony_ci	},
25662306a36Sopenharmony_ci	.tx = {
25762306a36Sopenharmony_ci		.tx_energy_detection         = 0,
25862306a36Sopenharmony_ci		.sta_rc_conf                 = {
25962306a36Sopenharmony_ci			.enabled_rates       = 0,
26062306a36Sopenharmony_ci			.short_retry_limit   = 10,
26162306a36Sopenharmony_ci			.long_retry_limit    = 10,
26262306a36Sopenharmony_ci			.aflags              = 0,
26362306a36Sopenharmony_ci		},
26462306a36Sopenharmony_ci		.ac_conf_count               = 4,
26562306a36Sopenharmony_ci		.ac_conf                     = {
26662306a36Sopenharmony_ci			[CONF_TX_AC_BE] = {
26762306a36Sopenharmony_ci				.ac          = CONF_TX_AC_BE,
26862306a36Sopenharmony_ci				.cw_min      = 15,
26962306a36Sopenharmony_ci				.cw_max      = 63,
27062306a36Sopenharmony_ci				.aifsn       = 3,
27162306a36Sopenharmony_ci				.tx_op_limit = 0,
27262306a36Sopenharmony_ci			},
27362306a36Sopenharmony_ci			[CONF_TX_AC_BK] = {
27462306a36Sopenharmony_ci				.ac          = CONF_TX_AC_BK,
27562306a36Sopenharmony_ci				.cw_min      = 15,
27662306a36Sopenharmony_ci				.cw_max      = 63,
27762306a36Sopenharmony_ci				.aifsn       = 7,
27862306a36Sopenharmony_ci				.tx_op_limit = 0,
27962306a36Sopenharmony_ci			},
28062306a36Sopenharmony_ci			[CONF_TX_AC_VI] = {
28162306a36Sopenharmony_ci				.ac          = CONF_TX_AC_VI,
28262306a36Sopenharmony_ci				.cw_min      = 15,
28362306a36Sopenharmony_ci				.cw_max      = 63,
28462306a36Sopenharmony_ci				.aifsn       = CONF_TX_AIFS_PIFS,
28562306a36Sopenharmony_ci				.tx_op_limit = 3008,
28662306a36Sopenharmony_ci			},
28762306a36Sopenharmony_ci			[CONF_TX_AC_VO] = {
28862306a36Sopenharmony_ci				.ac          = CONF_TX_AC_VO,
28962306a36Sopenharmony_ci				.cw_min      = 15,
29062306a36Sopenharmony_ci				.cw_max      = 63,
29162306a36Sopenharmony_ci				.aifsn       = CONF_TX_AIFS_PIFS,
29262306a36Sopenharmony_ci				.tx_op_limit = 1504,
29362306a36Sopenharmony_ci			},
29462306a36Sopenharmony_ci		},
29562306a36Sopenharmony_ci		.max_tx_retries = 100,
29662306a36Sopenharmony_ci		.ap_aging_period = 300,
29762306a36Sopenharmony_ci		.tid_conf_count = 4,
29862306a36Sopenharmony_ci		.tid_conf = {
29962306a36Sopenharmony_ci			[CONF_TX_AC_BE] = {
30062306a36Sopenharmony_ci				.queue_id    = CONF_TX_AC_BE,
30162306a36Sopenharmony_ci				.channel_type = CONF_CHANNEL_TYPE_EDCF,
30262306a36Sopenharmony_ci				.tsid        = CONF_TX_AC_BE,
30362306a36Sopenharmony_ci				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
30462306a36Sopenharmony_ci				.ack_policy  = CONF_ACK_POLICY_LEGACY,
30562306a36Sopenharmony_ci				.apsd_conf   = {0, 0},
30662306a36Sopenharmony_ci			},
30762306a36Sopenharmony_ci			[CONF_TX_AC_BK] = {
30862306a36Sopenharmony_ci				.queue_id    = CONF_TX_AC_BK,
30962306a36Sopenharmony_ci				.channel_type = CONF_CHANNEL_TYPE_EDCF,
31062306a36Sopenharmony_ci				.tsid        = CONF_TX_AC_BK,
31162306a36Sopenharmony_ci				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
31262306a36Sopenharmony_ci				.ack_policy  = CONF_ACK_POLICY_LEGACY,
31362306a36Sopenharmony_ci				.apsd_conf   = {0, 0},
31462306a36Sopenharmony_ci			},
31562306a36Sopenharmony_ci			[CONF_TX_AC_VI] = {
31662306a36Sopenharmony_ci				.queue_id    = CONF_TX_AC_VI,
31762306a36Sopenharmony_ci				.channel_type = CONF_CHANNEL_TYPE_EDCF,
31862306a36Sopenharmony_ci				.tsid        = CONF_TX_AC_VI,
31962306a36Sopenharmony_ci				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
32062306a36Sopenharmony_ci				.ack_policy  = CONF_ACK_POLICY_LEGACY,
32162306a36Sopenharmony_ci				.apsd_conf   = {0, 0},
32262306a36Sopenharmony_ci			},
32362306a36Sopenharmony_ci			[CONF_TX_AC_VO] = {
32462306a36Sopenharmony_ci				.queue_id    = CONF_TX_AC_VO,
32562306a36Sopenharmony_ci				.channel_type = CONF_CHANNEL_TYPE_EDCF,
32662306a36Sopenharmony_ci				.tsid        = CONF_TX_AC_VO,
32762306a36Sopenharmony_ci				.ps_scheme   = CONF_PS_SCHEME_LEGACY,
32862306a36Sopenharmony_ci				.ack_policy  = CONF_ACK_POLICY_LEGACY,
32962306a36Sopenharmony_ci				.apsd_conf   = {0, 0},
33062306a36Sopenharmony_ci			},
33162306a36Sopenharmony_ci		},
33262306a36Sopenharmony_ci		.frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
33362306a36Sopenharmony_ci		.tx_compl_timeout            = 350,
33462306a36Sopenharmony_ci		.tx_compl_threshold          = 10,
33562306a36Sopenharmony_ci		.basic_rate                  = CONF_HW_BIT_RATE_1MBPS,
33662306a36Sopenharmony_ci		.basic_rate_5                = CONF_HW_BIT_RATE_6MBPS,
33762306a36Sopenharmony_ci		.tmpl_short_retry_limit      = 10,
33862306a36Sopenharmony_ci		.tmpl_long_retry_limit       = 10,
33962306a36Sopenharmony_ci		.tx_watchdog_timeout         = 5000,
34062306a36Sopenharmony_ci		.slow_link_thold             = 3,
34162306a36Sopenharmony_ci		.fast_link_thold             = 30,
34262306a36Sopenharmony_ci	},
34362306a36Sopenharmony_ci	.conn = {
34462306a36Sopenharmony_ci		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
34562306a36Sopenharmony_ci		.listen_interval             = 1,
34662306a36Sopenharmony_ci		.suspend_wake_up_event       = CONF_WAKE_UP_EVENT_N_DTIM,
34762306a36Sopenharmony_ci		.suspend_listen_interval     = 3,
34862306a36Sopenharmony_ci		.bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
34962306a36Sopenharmony_ci		.bcn_filt_ie_count           = 3,
35062306a36Sopenharmony_ci		.bcn_filt_ie = {
35162306a36Sopenharmony_ci			[0] = {
35262306a36Sopenharmony_ci				.ie          = WLAN_EID_CHANNEL_SWITCH,
35362306a36Sopenharmony_ci				.rule        = CONF_BCN_RULE_PASS_ON_APPEARANCE,
35462306a36Sopenharmony_ci			},
35562306a36Sopenharmony_ci			[1] = {
35662306a36Sopenharmony_ci				.ie          = WLAN_EID_HT_OPERATION,
35762306a36Sopenharmony_ci				.rule        = CONF_BCN_RULE_PASS_ON_CHANGE,
35862306a36Sopenharmony_ci			},
35962306a36Sopenharmony_ci			[2] = {
36062306a36Sopenharmony_ci				.ie	     = WLAN_EID_ERP_INFO,
36162306a36Sopenharmony_ci				.rule	     = CONF_BCN_RULE_PASS_ON_CHANGE,
36262306a36Sopenharmony_ci			},
36362306a36Sopenharmony_ci		},
36462306a36Sopenharmony_ci		.synch_fail_thold            = 12,
36562306a36Sopenharmony_ci		.bss_lose_timeout            = 400,
36662306a36Sopenharmony_ci		.beacon_rx_timeout           = 10000,
36762306a36Sopenharmony_ci		.broadcast_timeout           = 20000,
36862306a36Sopenharmony_ci		.rx_broadcast_in_ps          = 1,
36962306a36Sopenharmony_ci		.ps_poll_threshold           = 10,
37062306a36Sopenharmony_ci		.bet_enable                  = CONF_BET_MODE_ENABLE,
37162306a36Sopenharmony_ci		.bet_max_consecutive         = 50,
37262306a36Sopenharmony_ci		.psm_entry_retries           = 8,
37362306a36Sopenharmony_ci		.psm_exit_retries            = 16,
37462306a36Sopenharmony_ci		.psm_entry_nullfunc_retries  = 3,
37562306a36Sopenharmony_ci		.dynamic_ps_timeout          = 1500,
37662306a36Sopenharmony_ci		.forced_ps                   = false,
37762306a36Sopenharmony_ci		.keep_alive_interval         = 55000,
37862306a36Sopenharmony_ci		.max_listen_interval         = 20,
37962306a36Sopenharmony_ci		.sta_sleep_auth              = WL1271_PSM_ILLEGAL,
38062306a36Sopenharmony_ci		.suspend_rx_ba_activity      = 0,
38162306a36Sopenharmony_ci	},
38262306a36Sopenharmony_ci	.itrim = {
38362306a36Sopenharmony_ci		.enable = false,
38462306a36Sopenharmony_ci		.timeout = 50000,
38562306a36Sopenharmony_ci	},
38662306a36Sopenharmony_ci	.pm_config = {
38762306a36Sopenharmony_ci		.host_clk_settling_time = 5000,
38862306a36Sopenharmony_ci		.host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE,
38962306a36Sopenharmony_ci	},
39062306a36Sopenharmony_ci	.roam_trigger = {
39162306a36Sopenharmony_ci		.trigger_pacing               = 1,
39262306a36Sopenharmony_ci		.avg_weight_rssi_beacon       = 20,
39362306a36Sopenharmony_ci		.avg_weight_rssi_data         = 10,
39462306a36Sopenharmony_ci		.avg_weight_snr_beacon        = 20,
39562306a36Sopenharmony_ci		.avg_weight_snr_data          = 10,
39662306a36Sopenharmony_ci	},
39762306a36Sopenharmony_ci	.scan = {
39862306a36Sopenharmony_ci		.min_dwell_time_active        = 7500,
39962306a36Sopenharmony_ci		.max_dwell_time_active        = 30000,
40062306a36Sopenharmony_ci		.min_dwell_time_active_long   = 25000,
40162306a36Sopenharmony_ci		.max_dwell_time_active_long   = 50000,
40262306a36Sopenharmony_ci		.dwell_time_passive           = 100000,
40362306a36Sopenharmony_ci		.dwell_time_dfs               = 150000,
40462306a36Sopenharmony_ci		.num_probe_reqs               = 2,
40562306a36Sopenharmony_ci		.split_scan_timeout           = 50000,
40662306a36Sopenharmony_ci	},
40762306a36Sopenharmony_ci	.sched_scan = {
40862306a36Sopenharmony_ci		/*
40962306a36Sopenharmony_ci		 * Values are in TU/1000 but since sched scan FW command
41062306a36Sopenharmony_ci		 * params are in TUs rounding up may occur.
41162306a36Sopenharmony_ci		 */
41262306a36Sopenharmony_ci		.base_dwell_time		= 7500,
41362306a36Sopenharmony_ci		.max_dwell_time_delta		= 22500,
41462306a36Sopenharmony_ci		/* based on 250bits per probe @1Mbps */
41562306a36Sopenharmony_ci		.dwell_time_delta_per_probe	= 2000,
41662306a36Sopenharmony_ci		/* based on 250bits per probe @6Mbps (plus a bit more) */
41762306a36Sopenharmony_ci		.dwell_time_delta_per_probe_5	= 350,
41862306a36Sopenharmony_ci		.dwell_time_passive		= 100000,
41962306a36Sopenharmony_ci		.dwell_time_dfs			= 150000,
42062306a36Sopenharmony_ci		.num_probe_reqs			= 2,
42162306a36Sopenharmony_ci		.rssi_threshold			= -90,
42262306a36Sopenharmony_ci		.snr_threshold			= 0,
42362306a36Sopenharmony_ci		.num_short_intervals		= SCAN_MAX_SHORT_INTERVALS,
42462306a36Sopenharmony_ci		.long_interval			= 30000,
42562306a36Sopenharmony_ci	},
42662306a36Sopenharmony_ci	.ht = {
42762306a36Sopenharmony_ci		.rx_ba_win_size = 32,
42862306a36Sopenharmony_ci		.tx_ba_win_size = 64,
42962306a36Sopenharmony_ci		.inactivity_timeout = 10000,
43062306a36Sopenharmony_ci		.tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
43162306a36Sopenharmony_ci	},
43262306a36Sopenharmony_ci	.mem = {
43362306a36Sopenharmony_ci		.num_stations                 = 1,
43462306a36Sopenharmony_ci		.ssid_profiles                = 1,
43562306a36Sopenharmony_ci		.rx_block_num                 = 40,
43662306a36Sopenharmony_ci		.tx_min_block_num             = 40,
43762306a36Sopenharmony_ci		.dynamic_memory               = 1,
43862306a36Sopenharmony_ci		.min_req_tx_blocks            = 45,
43962306a36Sopenharmony_ci		.min_req_rx_blocks            = 22,
44062306a36Sopenharmony_ci		.tx_min                       = 27,
44162306a36Sopenharmony_ci	},
44262306a36Sopenharmony_ci	.fm_coex = {
44362306a36Sopenharmony_ci		.enable                       = true,
44462306a36Sopenharmony_ci		.swallow_period               = 5,
44562306a36Sopenharmony_ci		.n_divider_fref_set_1         = 0xff,       /* default */
44662306a36Sopenharmony_ci		.n_divider_fref_set_2         = 12,
44762306a36Sopenharmony_ci		.m_divider_fref_set_1         = 0xffff,
44862306a36Sopenharmony_ci		.m_divider_fref_set_2         = 148,        /* default */
44962306a36Sopenharmony_ci		.coex_pll_stabilization_time  = 0xffffffff, /* default */
45062306a36Sopenharmony_ci		.ldo_stabilization_time       = 0xffff,     /* default */
45162306a36Sopenharmony_ci		.fm_disturbed_band_margin     = 0xff,       /* default */
45262306a36Sopenharmony_ci		.swallow_clk_diff             = 0xff,       /* default */
45362306a36Sopenharmony_ci	},
45462306a36Sopenharmony_ci	.rx_streaming = {
45562306a36Sopenharmony_ci		.duration                      = 150,
45662306a36Sopenharmony_ci		.queues                        = 0x1,
45762306a36Sopenharmony_ci		.interval                      = 20,
45862306a36Sopenharmony_ci		.always                        = 0,
45962306a36Sopenharmony_ci	},
46062306a36Sopenharmony_ci	.fwlog = {
46162306a36Sopenharmony_ci		.mode                         = WL12XX_FWLOG_CONTINUOUS,
46262306a36Sopenharmony_ci		.mem_blocks                   = 0,
46362306a36Sopenharmony_ci		.severity                     = 0,
46462306a36Sopenharmony_ci		.timestamp                    = WL12XX_FWLOG_TIMESTAMP_DISABLED,
46562306a36Sopenharmony_ci		.output                       = WL12XX_FWLOG_OUTPUT_DBG_PINS,
46662306a36Sopenharmony_ci		.threshold                    = 0,
46762306a36Sopenharmony_ci	},
46862306a36Sopenharmony_ci	.rate = {
46962306a36Sopenharmony_ci		.rate_retry_score = 32000,
47062306a36Sopenharmony_ci		.per_add = 8192,
47162306a36Sopenharmony_ci		.per_th1 = 2048,
47262306a36Sopenharmony_ci		.per_th2 = 4096,
47362306a36Sopenharmony_ci		.max_per = 8100,
47462306a36Sopenharmony_ci		.inverse_curiosity_factor = 5,
47562306a36Sopenharmony_ci		.tx_fail_low_th = 4,
47662306a36Sopenharmony_ci		.tx_fail_high_th = 10,
47762306a36Sopenharmony_ci		.per_alpha_shift = 4,
47862306a36Sopenharmony_ci		.per_add_shift = 13,
47962306a36Sopenharmony_ci		.per_beta1_shift = 10,
48062306a36Sopenharmony_ci		.per_beta2_shift = 8,
48162306a36Sopenharmony_ci		.rate_check_up = 2,
48262306a36Sopenharmony_ci		.rate_check_down = 12,
48362306a36Sopenharmony_ci		.rate_retry_policy = {
48462306a36Sopenharmony_ci			0x00, 0x00, 0x00, 0x00, 0x00,
48562306a36Sopenharmony_ci			0x00, 0x00, 0x00, 0x00, 0x00,
48662306a36Sopenharmony_ci			0x00, 0x00, 0x00,
48762306a36Sopenharmony_ci		},
48862306a36Sopenharmony_ci	},
48962306a36Sopenharmony_ci	.hangover = {
49062306a36Sopenharmony_ci		.recover_time               = 0,
49162306a36Sopenharmony_ci		.hangover_period            = 20,
49262306a36Sopenharmony_ci		.dynamic_mode               = 1,
49362306a36Sopenharmony_ci		.early_termination_mode     = 1,
49462306a36Sopenharmony_ci		.max_period                 = 20,
49562306a36Sopenharmony_ci		.min_period                 = 1,
49662306a36Sopenharmony_ci		.increase_delta             = 1,
49762306a36Sopenharmony_ci		.decrease_delta             = 2,
49862306a36Sopenharmony_ci		.quiet_time                 = 4,
49962306a36Sopenharmony_ci		.increase_time              = 1,
50062306a36Sopenharmony_ci		.window_size                = 16,
50162306a36Sopenharmony_ci	},
50262306a36Sopenharmony_ci	.recovery = {
50362306a36Sopenharmony_ci		.bug_on_recovery	    = 0,
50462306a36Sopenharmony_ci		.no_recovery		    = 0,
50562306a36Sopenharmony_ci	},
50662306a36Sopenharmony_ci};
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic struct wl18xx_priv_conf wl18xx_default_priv_conf = {
50962306a36Sopenharmony_ci	.ht = {
51062306a36Sopenharmony_ci		.mode				= HT_MODE_WIDE,
51162306a36Sopenharmony_ci	},
51262306a36Sopenharmony_ci	.phy = {
51362306a36Sopenharmony_ci		.phy_standalone			= 0x00,
51462306a36Sopenharmony_ci		.primary_clock_setting_time	= 0x05,
51562306a36Sopenharmony_ci		.clock_valid_on_wake_up		= 0x00,
51662306a36Sopenharmony_ci		.secondary_clock_setting_time	= 0x05,
51762306a36Sopenharmony_ci		.board_type 			= BOARD_TYPE_HDK_18XX,
51862306a36Sopenharmony_ci		.auto_detect			= 0x00,
51962306a36Sopenharmony_ci		.dedicated_fem			= FEM_NONE,
52062306a36Sopenharmony_ci		.low_band_component		= COMPONENT_3_WAY_SWITCH,
52162306a36Sopenharmony_ci		.low_band_component_type	= 0x05,
52262306a36Sopenharmony_ci		.high_band_component		= COMPONENT_2_WAY_SWITCH,
52362306a36Sopenharmony_ci		.high_band_component_type	= 0x09,
52462306a36Sopenharmony_ci		.tcxo_ldo_voltage		= 0x00,
52562306a36Sopenharmony_ci		.xtal_itrim_val			= 0x04,
52662306a36Sopenharmony_ci		.srf_state			= 0x00,
52762306a36Sopenharmony_ci		.io_configuration		= 0x01,
52862306a36Sopenharmony_ci		.sdio_configuration		= 0x00,
52962306a36Sopenharmony_ci		.settings			= 0x00,
53062306a36Sopenharmony_ci		.enable_clpc			= 0x00,
53162306a36Sopenharmony_ci		.enable_tx_low_pwr_on_siso_rdl	= 0x00,
53262306a36Sopenharmony_ci		.rx_profile			= 0x00,
53362306a36Sopenharmony_ci		.pwr_limit_reference_11_abg	= 0x64,
53462306a36Sopenharmony_ci		.per_chan_pwr_limit_arr_11abg	= {
53562306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53662306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53762306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53862306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53962306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54062306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54162306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54262306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54362306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54462306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54562306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54662306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54762306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54862306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54962306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55062306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55162306a36Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
55262306a36Sopenharmony_ci		.pwr_limit_reference_11p	= 0x64,
55362306a36Sopenharmony_ci		.per_chan_bo_mode_11_abg	= { 0x00, 0x00, 0x00, 0x00,
55462306a36Sopenharmony_ci						    0x00, 0x00, 0x00, 0x00,
55562306a36Sopenharmony_ci						    0x00, 0x00, 0x00, 0x00,
55662306a36Sopenharmony_ci						    0x00 },
55762306a36Sopenharmony_ci		.per_chan_bo_mode_11_p		= { 0x00, 0x00, 0x00, 0x00 },
55862306a36Sopenharmony_ci		.per_chan_pwr_limit_arr_11p	= { 0xff, 0xff, 0xff, 0xff,
55962306a36Sopenharmony_ci						    0xff, 0xff, 0xff },
56062306a36Sopenharmony_ci		.psat				= 0,
56162306a36Sopenharmony_ci		.external_pa_dc2dc		= 0,
56262306a36Sopenharmony_ci		.number_of_assembled_ant2_4	= 2,
56362306a36Sopenharmony_ci		.number_of_assembled_ant5	= 1,
56462306a36Sopenharmony_ci		.low_power_val			= 0xff,
56562306a36Sopenharmony_ci		.med_power_val			= 0xff,
56662306a36Sopenharmony_ci		.high_power_val			= 0xff,
56762306a36Sopenharmony_ci		.low_power_val_2nd		= 0xff,
56862306a36Sopenharmony_ci		.med_power_val_2nd		= 0xff,
56962306a36Sopenharmony_ci		.high_power_val_2nd		= 0xff,
57062306a36Sopenharmony_ci		.tx_rf_margin			= 1,
57162306a36Sopenharmony_ci	},
57262306a36Sopenharmony_ci	.ap_sleep = {               /* disabled by default */
57362306a36Sopenharmony_ci		.idle_duty_cycle        = 0,
57462306a36Sopenharmony_ci		.connected_duty_cycle   = 0,
57562306a36Sopenharmony_ci		.max_stations_thresh    = 0,
57662306a36Sopenharmony_ci		.idle_conn_thresh       = 0,
57762306a36Sopenharmony_ci	},
57862306a36Sopenharmony_ci};
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
58162306a36Sopenharmony_ci	[PART_TOP_PRCM_ELP_SOC] = {
58262306a36Sopenharmony_ci		.mem  = { .start = 0x00A00000, .size  = 0x00012000 },
58362306a36Sopenharmony_ci		.reg  = { .start = 0x00807000, .size  = 0x00005000 },
58462306a36Sopenharmony_ci		.mem2 = { .start = 0x00800000, .size  = 0x0000B000 },
58562306a36Sopenharmony_ci		.mem3 = { .start = 0x00401594, .size  = 0x00001020 },
58662306a36Sopenharmony_ci	},
58762306a36Sopenharmony_ci	[PART_DOWN] = {
58862306a36Sopenharmony_ci		.mem  = { .start = 0x00000000, .size  = 0x00014000 },
58962306a36Sopenharmony_ci		.reg  = { .start = 0x00810000, .size  = 0x0000BFFF },
59062306a36Sopenharmony_ci		.mem2 = { .start = 0x00000000, .size  = 0x00000000 },
59162306a36Sopenharmony_ci		.mem3 = { .start = 0x00000000, .size  = 0x00000000 },
59262306a36Sopenharmony_ci	},
59362306a36Sopenharmony_ci	[PART_BOOT] = {
59462306a36Sopenharmony_ci		.mem  = { .start = 0x00700000, .size = 0x0000030c },
59562306a36Sopenharmony_ci		.reg  = { .start = 0x00802000, .size = 0x00014578 },
59662306a36Sopenharmony_ci		.mem2 = { .start = 0x00B00404, .size = 0x00001000 },
59762306a36Sopenharmony_ci		.mem3 = { .start = 0x00C00000, .size = 0x00000400 },
59862306a36Sopenharmony_ci	},
59962306a36Sopenharmony_ci	[PART_WORK] = {
60062306a36Sopenharmony_ci		.mem  = { .start = 0x00800000, .size  = 0x000050FC },
60162306a36Sopenharmony_ci		.reg  = { .start = 0x00B00404, .size  = 0x00001000 },
60262306a36Sopenharmony_ci		.mem2 = { .start = 0x00C00000, .size  = 0x00000400 },
60362306a36Sopenharmony_ci		.mem3 = { .start = 0x00401594, .size  = 0x00001020 },
60462306a36Sopenharmony_ci	},
60562306a36Sopenharmony_ci	[PART_PHY_INIT] = {
60662306a36Sopenharmony_ci		.mem  = { .start = WL18XX_PHY_INIT_MEM_ADDR,
60762306a36Sopenharmony_ci			  .size  = WL18XX_PHY_INIT_MEM_SIZE },
60862306a36Sopenharmony_ci		.reg  = { .start = 0x00000000, .size = 0x00000000 },
60962306a36Sopenharmony_ci		.mem2 = { .start = 0x00000000, .size = 0x00000000 },
61062306a36Sopenharmony_ci		.mem3 = { .start = 0x00000000, .size = 0x00000000 },
61162306a36Sopenharmony_ci	},
61262306a36Sopenharmony_ci};
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic const int wl18xx_rtable[REG_TABLE_LEN] = {
61562306a36Sopenharmony_ci	[REG_ECPU_CONTROL]		= WL18XX_REG_ECPU_CONTROL,
61662306a36Sopenharmony_ci	[REG_INTERRUPT_NO_CLEAR]	= WL18XX_REG_INTERRUPT_NO_CLEAR,
61762306a36Sopenharmony_ci	[REG_INTERRUPT_ACK]		= WL18XX_REG_INTERRUPT_ACK,
61862306a36Sopenharmony_ci	[REG_COMMAND_MAILBOX_PTR]	= WL18XX_REG_COMMAND_MAILBOX_PTR,
61962306a36Sopenharmony_ci	[REG_EVENT_MAILBOX_PTR]		= WL18XX_REG_EVENT_MAILBOX_PTR,
62062306a36Sopenharmony_ci	[REG_INTERRUPT_TRIG]		= WL18XX_REG_INTERRUPT_TRIG_H,
62162306a36Sopenharmony_ci	[REG_INTERRUPT_MASK]		= WL18XX_REG_INTERRUPT_MASK,
62262306a36Sopenharmony_ci	[REG_PC_ON_RECOVERY]		= WL18XX_SCR_PAD4,
62362306a36Sopenharmony_ci	[REG_CHIP_ID_B]			= WL18XX_REG_CHIP_ID_B,
62462306a36Sopenharmony_ci	[REG_CMD_MBOX_ADDRESS]		= WL18XX_CMD_MBOX_ADDRESS,
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* data access memory addresses, used with partition translation */
62762306a36Sopenharmony_ci	[REG_SLV_MEM_DATA]		= WL18XX_SLV_MEM_DATA,
62862306a36Sopenharmony_ci	[REG_SLV_REG_DATA]		= WL18XX_SLV_REG_DATA,
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* raw data access memory addresses */
63162306a36Sopenharmony_ci	[REG_RAW_FW_STATUS_ADDR]	= WL18XX_FW_STATUS_ADDR,
63262306a36Sopenharmony_ci};
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic const struct wl18xx_clk_cfg wl18xx_clk_table_coex[NUM_CLOCK_CONFIGS] = {
63562306a36Sopenharmony_ci	[CLOCK_CONFIG_16_2_M]	= { 8,  121, 0, 0, false },
63662306a36Sopenharmony_ci	[CLOCK_CONFIG_16_368_M]	= { 8,  120, 0, 0, false },
63762306a36Sopenharmony_ci	[CLOCK_CONFIG_16_8_M]	= { 8,  117, 0, 0, false },
63862306a36Sopenharmony_ci	[CLOCK_CONFIG_19_2_M]	= { 10, 128, 0, 0, false },
63962306a36Sopenharmony_ci	[CLOCK_CONFIG_26_M]	= { 11, 104, 0, 0, false },
64062306a36Sopenharmony_ci	[CLOCK_CONFIG_32_736_M]	= { 8,  120, 0, 0, false },
64162306a36Sopenharmony_ci	[CLOCK_CONFIG_33_6_M]	= { 8,  117, 0, 0, false },
64262306a36Sopenharmony_ci	[CLOCK_CONFIG_38_468_M]	= { 10, 128, 0, 0, false },
64362306a36Sopenharmony_ci	[CLOCK_CONFIG_52_M]	= { 11, 104, 0, 0, false },
64462306a36Sopenharmony_ci};
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
64762306a36Sopenharmony_ci	[CLOCK_CONFIG_16_2_M]	= { 7,  104,  801, 4,  true },
64862306a36Sopenharmony_ci	[CLOCK_CONFIG_16_368_M]	= { 9,  132, 3751, 4,  true },
64962306a36Sopenharmony_ci	[CLOCK_CONFIG_16_8_M]	= { 7,  100,    0, 0, false },
65062306a36Sopenharmony_ci	[CLOCK_CONFIG_19_2_M]	= { 8,  100,    0, 0, false },
65162306a36Sopenharmony_ci	[CLOCK_CONFIG_26_M]	= { 13, 120,    0, 0, false },
65262306a36Sopenharmony_ci	[CLOCK_CONFIG_32_736_M]	= { 9,  132, 3751, 4,  true },
65362306a36Sopenharmony_ci	[CLOCK_CONFIG_33_6_M]	= { 7,  100,    0, 0, false },
65462306a36Sopenharmony_ci	[CLOCK_CONFIG_38_468_M]	= { 8,  100,    0, 0, false },
65562306a36Sopenharmony_ci	[CLOCK_CONFIG_52_M]	= { 13, 120,    0, 0, false },
65662306a36Sopenharmony_ci};
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci/* TODO: maybe move to a new header file? */
65962306a36Sopenharmony_ci#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-4.bin"
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int wl18xx_identify_chip(struct wl1271 *wl)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	int ret = 0;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	switch (wl->chip.id) {
66662306a36Sopenharmony_ci	case CHIP_ID_185x_PG20:
66762306a36Sopenharmony_ci		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG20)",
66862306a36Sopenharmony_ci				 wl->chip.id);
66962306a36Sopenharmony_ci		wl->sr_fw_name = WL18XX_FW_NAME;
67062306a36Sopenharmony_ci		/* wl18xx uses the same firmware for PLT */
67162306a36Sopenharmony_ci		wl->plt_fw_name = WL18XX_FW_NAME;
67262306a36Sopenharmony_ci		wl->quirks |= WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN |
67362306a36Sopenharmony_ci			      WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN |
67462306a36Sopenharmony_ci			      WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN |
67562306a36Sopenharmony_ci			      WLCORE_QUIRK_TX_PAD_LAST_FRAME |
67662306a36Sopenharmony_ci			      WLCORE_QUIRK_REGDOMAIN_CONF |
67762306a36Sopenharmony_ci			      WLCORE_QUIRK_DUAL_PROBE_TMPL;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER,
68062306a36Sopenharmony_ci				      WL18XX_IFTYPE_VER,  WL18XX_MAJOR_VER,
68162306a36Sopenharmony_ci				      WL18XX_SUBTYPE_VER, WL18XX_MINOR_VER,
68262306a36Sopenharmony_ci				      /* there's no separate multi-role FW */
68362306a36Sopenharmony_ci				      0, 0, 0, 0);
68462306a36Sopenharmony_ci		break;
68562306a36Sopenharmony_ci	case CHIP_ID_185x_PG10:
68662306a36Sopenharmony_ci		wl1271_warning("chip id 0x%x (185x PG10) is deprecated",
68762306a36Sopenharmony_ci			       wl->chip.id);
68862306a36Sopenharmony_ci		ret = -ENODEV;
68962306a36Sopenharmony_ci		goto out;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	default:
69262306a36Sopenharmony_ci		wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
69362306a36Sopenharmony_ci		ret = -ENODEV;
69462306a36Sopenharmony_ci		goto out;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	wl->fw_mem_block_size = 272;
69862306a36Sopenharmony_ci	wl->fwlog_end = 0x40000000;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	wl->scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
70162306a36Sopenharmony_ci	wl->scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
70262306a36Sopenharmony_ci	wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
70362306a36Sopenharmony_ci	wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
70462306a36Sopenharmony_ci	wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
70562306a36Sopenharmony_ci	wl->ba_rx_session_count_max = WL18XX_RX_BA_MAX_SESSIONS;
70662306a36Sopenharmony_ciout:
70762306a36Sopenharmony_ci	return ret;
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic int wl18xx_set_clk(struct wl1271 *wl)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	u16 clk_freq;
71362306a36Sopenharmony_ci	int ret;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
71662306a36Sopenharmony_ci	if (ret < 0)
71762306a36Sopenharmony_ci		goto out;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/* TODO: PG2: apparently we need to read the clk type */
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	ret = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT, &clk_freq);
72262306a36Sopenharmony_ci	if (ret < 0)
72362306a36Sopenharmony_ci		goto out;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq,
72662306a36Sopenharmony_ci		     wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m,
72762306a36Sopenharmony_ci		     wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q,
72862306a36Sopenharmony_ci		     wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit");
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/* coex PLL configuration */
73162306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_N,
73262306a36Sopenharmony_ci				   wl18xx_clk_table_coex[clk_freq].n);
73362306a36Sopenharmony_ci	if (ret < 0)
73462306a36Sopenharmony_ci		goto out;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_M,
73762306a36Sopenharmony_ci				   wl18xx_clk_table_coex[clk_freq].m);
73862306a36Sopenharmony_ci	if (ret < 0)
73962306a36Sopenharmony_ci		goto out;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* bypass the swallowing logic */
74262306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
74362306a36Sopenharmony_ci				   PLLSH_COEX_PLL_SWALLOW_EN_VAL1);
74462306a36Sopenharmony_ci	if (ret < 0)
74562306a36Sopenharmony_ci		goto out;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
74862306a36Sopenharmony_ci				   wl18xx_clk_table[clk_freq].n);
74962306a36Sopenharmony_ci	if (ret < 0)
75062306a36Sopenharmony_ci		goto out;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M,
75362306a36Sopenharmony_ci				   wl18xx_clk_table[clk_freq].m);
75462306a36Sopenharmony_ci	if (ret < 0)
75562306a36Sopenharmony_ci		goto out;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (wl18xx_clk_table[clk_freq].swallow) {
75862306a36Sopenharmony_ci		/* first the 16 lower bits */
75962306a36Sopenharmony_ci		ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1,
76062306a36Sopenharmony_ci					   wl18xx_clk_table[clk_freq].q &
76162306a36Sopenharmony_ci					   PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK);
76262306a36Sopenharmony_ci		if (ret < 0)
76362306a36Sopenharmony_ci			goto out;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		/* then the 16 higher bits, masked out */
76662306a36Sopenharmony_ci		ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2,
76762306a36Sopenharmony_ci					(wl18xx_clk_table[clk_freq].q >> 16) &
76862306a36Sopenharmony_ci					PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK);
76962306a36Sopenharmony_ci		if (ret < 0)
77062306a36Sopenharmony_ci			goto out;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		/* first the 16 lower bits */
77362306a36Sopenharmony_ci		ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1,
77462306a36Sopenharmony_ci					   wl18xx_clk_table[clk_freq].p &
77562306a36Sopenharmony_ci					   PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK);
77662306a36Sopenharmony_ci		if (ret < 0)
77762306a36Sopenharmony_ci			goto out;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		/* then the 16 higher bits, masked out */
78062306a36Sopenharmony_ci		ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2,
78162306a36Sopenharmony_ci					(wl18xx_clk_table[clk_freq].p >> 16) &
78262306a36Sopenharmony_ci					PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK);
78362306a36Sopenharmony_ci		if (ret < 0)
78462306a36Sopenharmony_ci			goto out;
78562306a36Sopenharmony_ci	} else {
78662306a36Sopenharmony_ci		ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN,
78762306a36Sopenharmony_ci					   PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
78862306a36Sopenharmony_ci		if (ret < 0)
78962306a36Sopenharmony_ci			goto out;
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/* choose WCS PLL */
79362306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_SEL,
79462306a36Sopenharmony_ci				   PLLSH_WL_PLL_SEL_WCS_PLL);
79562306a36Sopenharmony_ci	if (ret < 0)
79662306a36Sopenharmony_ci		goto out;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	/* enable both PLLs */
79962306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL1);
80062306a36Sopenharmony_ci	if (ret < 0)
80162306a36Sopenharmony_ci		goto out;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	udelay(1000);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* disable coex PLL */
80662306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL2);
80762306a36Sopenharmony_ci	if (ret < 0)
80862306a36Sopenharmony_ci		goto out;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/* reset the swallowing logic */
81162306a36Sopenharmony_ci	ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
81262306a36Sopenharmony_ci				   PLLSH_COEX_PLL_SWALLOW_EN_VAL2);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ciout:
81562306a36Sopenharmony_ci	return ret;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic int wl18xx_boot_soft_reset(struct wl1271 *wl)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	int ret;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	/* disable Rx/Tx */
82362306a36Sopenharmony_ci	ret = wlcore_write32(wl, WL18XX_ENABLE, 0x0);
82462306a36Sopenharmony_ci	if (ret < 0)
82562306a36Sopenharmony_ci		goto out;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* disable auto calibration on start*/
82862306a36Sopenharmony_ci	ret = wlcore_write32(wl, WL18XX_SPARE_A2, 0xffff);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ciout:
83162306a36Sopenharmony_ci	return ret;
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_cistatic int wl18xx_pre_boot(struct wl1271 *wl)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	int ret;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	ret = wl18xx_set_clk(wl);
83962306a36Sopenharmony_ci	if (ret < 0)
84062306a36Sopenharmony_ci		goto out;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/* Continue the ELP wake up sequence */
84362306a36Sopenharmony_ci	ret = wlcore_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
84462306a36Sopenharmony_ci	if (ret < 0)
84562306a36Sopenharmony_ci		goto out;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	udelay(500);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
85062306a36Sopenharmony_ci	if (ret < 0)
85162306a36Sopenharmony_ci		goto out;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* Disable interrupts */
85462306a36Sopenharmony_ci	ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
85562306a36Sopenharmony_ci	if (ret < 0)
85662306a36Sopenharmony_ci		goto out;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	ret = wl18xx_boot_soft_reset(wl);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ciout:
86162306a36Sopenharmony_ci	return ret;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic int wl18xx_pre_upload(struct wl1271 *wl)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	u32 tmp;
86762306a36Sopenharmony_ci	int ret;
86862306a36Sopenharmony_ci	u16 irq_invert;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct wl18xx_mac_and_phy_params) >
87162306a36Sopenharmony_ci		WL18XX_PHY_INIT_MEM_SIZE);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
87462306a36Sopenharmony_ci	if (ret < 0)
87562306a36Sopenharmony_ci		goto out;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* TODO: check if this is all needed */
87862306a36Sopenharmony_ci	ret = wlcore_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND);
87962306a36Sopenharmony_ci	if (ret < 0)
88062306a36Sopenharmony_ci		goto out;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp);
88362306a36Sopenharmony_ci	if (ret < 0)
88462306a36Sopenharmony_ci		goto out;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp);
88962306a36Sopenharmony_ci	if (ret < 0)
89062306a36Sopenharmony_ci		goto out;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/*
89362306a36Sopenharmony_ci	 * Workaround for FDSP code RAM corruption (needed for PG2.1
89462306a36Sopenharmony_ci	 * and newer; for older chips it's a NOP).  Change FDSP clock
89562306a36Sopenharmony_ci	 * settings so that it's muxed to the ATGP clock instead of
89662306a36Sopenharmony_ci	 * its own clock.
89762306a36Sopenharmony_ci	 */
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
90062306a36Sopenharmony_ci	if (ret < 0)
90162306a36Sopenharmony_ci		goto out;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	/* disable FDSP clock */
90462306a36Sopenharmony_ci	ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
90562306a36Sopenharmony_ci			     MEM_FDSP_CLK_120_DISABLE);
90662306a36Sopenharmony_ci	if (ret < 0)
90762306a36Sopenharmony_ci		goto out;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	/* set ATPG clock toward FDSP Code RAM rather than its own clock */
91062306a36Sopenharmony_ci	ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
91162306a36Sopenharmony_ci			     MEM_FDSP_CODERAM_FUNC_CLK_SEL);
91262306a36Sopenharmony_ci	if (ret < 0)
91362306a36Sopenharmony_ci		goto out;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	/* re-enable FDSP clock */
91662306a36Sopenharmony_ci	ret = wlcore_write32(wl, WL18XX_PHY_FPGA_SPARE_1,
91762306a36Sopenharmony_ci			     MEM_FDSP_CLK_120_ENABLE);
91862306a36Sopenharmony_ci	if (ret < 0)
91962306a36Sopenharmony_ci		goto out;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	ret = irq_get_trigger_type(wl->irq);
92262306a36Sopenharmony_ci	if ((ret == IRQ_TYPE_LEVEL_LOW) || (ret == IRQ_TYPE_EDGE_FALLING)) {
92362306a36Sopenharmony_ci		wl1271_info("using inverted interrupt logic: %d", ret);
92462306a36Sopenharmony_ci		ret = wlcore_set_partition(wl,
92562306a36Sopenharmony_ci					   &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
92662306a36Sopenharmony_ci		if (ret < 0)
92762306a36Sopenharmony_ci			goto out;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		ret = wl18xx_top_reg_read(wl, TOP_FN0_CCCR_REG_32, &irq_invert);
93062306a36Sopenharmony_ci		if (ret < 0)
93162306a36Sopenharmony_ci			goto out;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci		irq_invert |= BIT(1);
93462306a36Sopenharmony_ci		ret = wl18xx_top_reg_write(wl, TOP_FN0_CCCR_REG_32, irq_invert);
93562306a36Sopenharmony_ci		if (ret < 0)
93662306a36Sopenharmony_ci			goto out;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ciout:
94262306a36Sopenharmony_ci	return ret;
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_cistatic int wl18xx_set_mac_and_phy(struct wl1271 *wl)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	struct wl18xx_priv *priv = wl->priv;
94862306a36Sopenharmony_ci	struct wl18xx_mac_and_phy_params *params;
94962306a36Sopenharmony_ci	int ret;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	params = kmemdup(&priv->conf.phy, sizeof(*params), GFP_KERNEL);
95262306a36Sopenharmony_ci	if (!params) {
95362306a36Sopenharmony_ci		ret = -ENOMEM;
95462306a36Sopenharmony_ci		goto out;
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]);
95862306a36Sopenharmony_ci	if (ret < 0)
95962306a36Sopenharmony_ci		goto out;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, params,
96262306a36Sopenharmony_ci			   sizeof(*params), false);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ciout:
96562306a36Sopenharmony_ci	kfree(params);
96662306a36Sopenharmony_ci	return ret;
96762306a36Sopenharmony_ci}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_cistatic int wl18xx_enable_interrupts(struct wl1271 *wl)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	u32 event_mask, intr_mask;
97262306a36Sopenharmony_ci	int ret;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	event_mask = WL18XX_ACX_EVENTS_VECTOR;
97562306a36Sopenharmony_ci	intr_mask = WL18XX_INTR_MASK;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask);
97862306a36Sopenharmony_ci	if (ret < 0)
97962306a36Sopenharmony_ci		goto out;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	wlcore_enable_interrupts(wl);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK,
98462306a36Sopenharmony_ci			       WL1271_ACX_INTR_ALL & ~intr_mask);
98562306a36Sopenharmony_ci	if (ret < 0)
98662306a36Sopenharmony_ci		goto disable_interrupts;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return ret;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cidisable_interrupts:
99162306a36Sopenharmony_ci	wlcore_disable_interrupts(wl);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ciout:
99462306a36Sopenharmony_ci	return ret;
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic int wl18xx_boot(struct wl1271 *wl)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	int ret;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	ret = wl18xx_pre_boot(wl);
100262306a36Sopenharmony_ci	if (ret < 0)
100362306a36Sopenharmony_ci		goto out;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	ret = wl18xx_pre_upload(wl);
100662306a36Sopenharmony_ci	if (ret < 0)
100762306a36Sopenharmony_ci		goto out;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	ret = wlcore_boot_upload_firmware(wl);
101062306a36Sopenharmony_ci	if (ret < 0)
101162306a36Sopenharmony_ci		goto out;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	ret = wl18xx_set_mac_and_phy(wl);
101462306a36Sopenharmony_ci	if (ret < 0)
101562306a36Sopenharmony_ci		goto out;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	wl->event_mask = BSS_LOSS_EVENT_ID |
101862306a36Sopenharmony_ci		SCAN_COMPLETE_EVENT_ID |
101962306a36Sopenharmony_ci		RADAR_DETECTED_EVENT_ID |
102062306a36Sopenharmony_ci		RSSI_SNR_TRIGGER_0_EVENT_ID |
102162306a36Sopenharmony_ci		PERIODIC_SCAN_COMPLETE_EVENT_ID |
102262306a36Sopenharmony_ci		PERIODIC_SCAN_REPORT_EVENT_ID |
102362306a36Sopenharmony_ci		DUMMY_PACKET_EVENT_ID |
102462306a36Sopenharmony_ci		PEER_REMOVE_COMPLETE_EVENT_ID |
102562306a36Sopenharmony_ci		BA_SESSION_RX_CONSTRAINT_EVENT_ID |
102662306a36Sopenharmony_ci		REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
102762306a36Sopenharmony_ci		INACTIVE_STA_EVENT_ID |
102862306a36Sopenharmony_ci		CHANNEL_SWITCH_COMPLETE_EVENT_ID |
102962306a36Sopenharmony_ci		DFS_CHANNELS_CONFIG_COMPLETE_EVENT |
103062306a36Sopenharmony_ci		SMART_CONFIG_SYNC_EVENT_ID |
103162306a36Sopenharmony_ci		SMART_CONFIG_DECODE_EVENT_ID |
103262306a36Sopenharmony_ci		TIME_SYNC_EVENT_ID |
103362306a36Sopenharmony_ci		FW_LOGGER_INDICATION |
103462306a36Sopenharmony_ci		RX_BA_WIN_SIZE_CHANGE_EVENT_ID;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	ret = wlcore_boot_run_firmware(wl);
103962306a36Sopenharmony_ci	if (ret < 0)
104062306a36Sopenharmony_ci		goto out;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	ret = wl18xx_enable_interrupts(wl);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ciout:
104562306a36Sopenharmony_ci	return ret;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic int wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr,
104962306a36Sopenharmony_ci			       void *buf, size_t len)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	struct wl18xx_priv *priv = wl->priv;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	memcpy(priv->cmd_buf, buf, len);
105462306a36Sopenharmony_ci	memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	return wlcore_write(wl, cmd_box_addr, priv->cmd_buf,
105762306a36Sopenharmony_ci			    WL18XX_CMD_MAX_SIZE, false);
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic int wl18xx_ack_event(struct wl1271 *wl)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	return wlcore_write_reg(wl, REG_INTERRUPT_TRIG,
106362306a36Sopenharmony_ci				WL18XX_INTR_TRIG_EVENT_ACK);
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_cistatic u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	u32 blk_size = WL18XX_TX_HW_BLOCK_SIZE;
106962306a36Sopenharmony_ci	return (len + blk_size - 1) / blk_size + spare_blks;
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic void
107362306a36Sopenharmony_ciwl18xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
107462306a36Sopenharmony_ci			  u32 blks, u32 spare_blks)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	desc->wl18xx_mem.total_mem_blocks = blks;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic void
108062306a36Sopenharmony_ciwl18xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc,
108162306a36Sopenharmony_ci			    struct sk_buff *skb)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	desc->length = cpu_to_le16(skb->len);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	/* if only the last frame is to be padded, we unset this bit on Tx */
108662306a36Sopenharmony_ci	if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME)
108762306a36Sopenharmony_ci		desc->wl18xx_mem.ctrl = WL18XX_TX_CTRL_NOT_PADDED;
108862306a36Sopenharmony_ci	else
108962306a36Sopenharmony_ci		desc->wl18xx_mem.ctrl = 0;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
109262306a36Sopenharmony_ci		     "len: %d life: %d mem: %d", desc->hlid,
109362306a36Sopenharmony_ci		     le16_to_cpu(desc->length),
109462306a36Sopenharmony_ci		     le16_to_cpu(desc->life_time),
109562306a36Sopenharmony_ci		     desc->wl18xx_mem.total_mem_blocks);
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_cistatic enum wl_rx_buf_align
109962306a36Sopenharmony_ciwl18xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	if (rx_desc & RX_BUF_PADDED_PAYLOAD)
110262306a36Sopenharmony_ci		return WLCORE_RX_BUF_PADDED;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	return WLCORE_RX_BUF_ALIGNED;
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic u32 wl18xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data,
110862306a36Sopenharmony_ci				    u32 data_len)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	struct wl1271_rx_descriptor *desc = rx_data;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/* invalid packet */
111362306a36Sopenharmony_ci	if (data_len < sizeof(*desc))
111462306a36Sopenharmony_ci		return 0;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return data_len - sizeof(*desc);
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic void wl18xx_tx_immediate_completion(struct wl1271 *wl)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	wl18xx_tx_immediate_complete(wl);
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cistatic int wl18xx_set_host_cfg_bitmap(struct wl1271 *wl, u32 extra_mem_blk)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	int ret;
112762306a36Sopenharmony_ci	u32 sdio_align_size = 0;
112862306a36Sopenharmony_ci	u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE |
112962306a36Sopenharmony_ci			      HOST_IF_CFG_ADD_RX_ALIGNMENT;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* Enable Tx SDIO padding */
113262306a36Sopenharmony_ci	if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) {
113362306a36Sopenharmony_ci		host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
113462306a36Sopenharmony_ci		sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	/* Enable Rx SDIO padding */
113862306a36Sopenharmony_ci	if (wl->quirks & WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN) {
113962306a36Sopenharmony_ci		host_cfg_bitmap |= HOST_IF_CFG_RX_PAD_TO_SDIO_BLK;
114062306a36Sopenharmony_ci		sdio_align_size = WL12XX_BUS_BLOCK_SIZE;
114162306a36Sopenharmony_ci	}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	ret = wl18xx_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap,
114462306a36Sopenharmony_ci					    sdio_align_size, extra_mem_blk,
114562306a36Sopenharmony_ci					    WL18XX_HOST_IF_LEN_SIZE_FIELD);
114662306a36Sopenharmony_ci	if (ret < 0)
114762306a36Sopenharmony_ci		return ret;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	return 0;
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic int wl18xx_hw_init(struct wl1271 *wl)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	int ret;
115562306a36Sopenharmony_ci	struct wl18xx_priv *priv = wl->priv;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	/* (re)init private structures. Relevant on recovery as well. */
115862306a36Sopenharmony_ci	priv->last_fw_rls_idx = 0;
115962306a36Sopenharmony_ci	priv->extra_spare_key_count = 0;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	/* set the default amount of spare blocks in the bitmap */
116262306a36Sopenharmony_ci	ret = wl18xx_set_host_cfg_bitmap(wl, WL18XX_TX_HW_BLOCK_SPARE);
116362306a36Sopenharmony_ci	if (ret < 0)
116462306a36Sopenharmony_ci		return ret;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	/* set the dynamic fw traces bitmap */
116762306a36Sopenharmony_ci	ret = wl18xx_acx_dynamic_fw_traces(wl);
116862306a36Sopenharmony_ci	if (ret < 0)
116962306a36Sopenharmony_ci		return ret;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	if (checksum_param) {
117262306a36Sopenharmony_ci		ret = wl18xx_acx_set_checksum_state(wl);
117362306a36Sopenharmony_ci		if (ret != 0)
117462306a36Sopenharmony_ci			return ret;
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	return ret;
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic void wl18xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status,
118162306a36Sopenharmony_ci				     struct wl_fw_status *fw_status)
118262306a36Sopenharmony_ci{
118362306a36Sopenharmony_ci	struct wl18xx_fw_status *int_fw_status = raw_fw_status;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	fw_status->intr = le32_to_cpu(int_fw_status->intr);
118662306a36Sopenharmony_ci	fw_status->fw_rx_counter = int_fw_status->fw_rx_counter;
118762306a36Sopenharmony_ci	fw_status->drv_rx_counter = int_fw_status->drv_rx_counter;
118862306a36Sopenharmony_ci	fw_status->tx_results_counter = int_fw_status->tx_results_counter;
118962306a36Sopenharmony_ci	fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime);
119262306a36Sopenharmony_ci	fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap);
119362306a36Sopenharmony_ci	fw_status->link_fast_bitmap =
119462306a36Sopenharmony_ci			le32_to_cpu(int_fw_status->link_fast_bitmap);
119562306a36Sopenharmony_ci	fw_status->total_released_blks =
119662306a36Sopenharmony_ci			le32_to_cpu(int_fw_status->total_released_blks);
119762306a36Sopenharmony_ci	fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	fw_status->counters.tx_released_pkts =
120062306a36Sopenharmony_ci			int_fw_status->counters.tx_released_pkts;
120162306a36Sopenharmony_ci	fw_status->counters.tx_lnk_free_pkts =
120262306a36Sopenharmony_ci			int_fw_status->counters.tx_lnk_free_pkts;
120362306a36Sopenharmony_ci	fw_status->counters.tx_voice_released_blks =
120462306a36Sopenharmony_ci			int_fw_status->counters.tx_voice_released_blks;
120562306a36Sopenharmony_ci	fw_status->counters.tx_last_rate =
120662306a36Sopenharmony_ci			int_fw_status->counters.tx_last_rate;
120762306a36Sopenharmony_ci	fw_status->counters.tx_last_rate_mbps =
120862306a36Sopenharmony_ci			int_fw_status->counters.tx_last_rate_mbps;
120962306a36Sopenharmony_ci	fw_status->counters.hlid =
121062306a36Sopenharmony_ci			int_fw_status->counters.hlid;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	fw_status->priv = &int_fw_status->priv;
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic void wl18xx_set_tx_desc_csum(struct wl1271 *wl,
121862306a36Sopenharmony_ci				    struct wl1271_tx_hw_descr *desc,
121962306a36Sopenharmony_ci				    struct sk_buff *skb)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	u32 ip_hdr_offset;
122262306a36Sopenharmony_ci	struct iphdr *ip_hdr;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if (!checksum_param) {
122562306a36Sopenharmony_ci		desc->wl18xx_checksum_data = 0;
122662306a36Sopenharmony_ci		return;
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (skb->ip_summed != CHECKSUM_PARTIAL) {
123062306a36Sopenharmony_ci		desc->wl18xx_checksum_data = 0;
123162306a36Sopenharmony_ci		return;
123262306a36Sopenharmony_ci	}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	ip_hdr_offset = skb_network_header(skb) - skb_mac_header(skb);
123562306a36Sopenharmony_ci	if (WARN_ON(ip_hdr_offset >= (1<<7))) {
123662306a36Sopenharmony_ci		desc->wl18xx_checksum_data = 0;
123762306a36Sopenharmony_ci		return;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	desc->wl18xx_checksum_data = ip_hdr_offset << 1;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	/* FW is interested only in the LSB of the protocol  TCP=0 UDP=1 */
124362306a36Sopenharmony_ci	ip_hdr = (void *)skb_network_header(skb);
124462306a36Sopenharmony_ci	desc->wl18xx_checksum_data |= (ip_hdr->protocol & 0x01);
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_cistatic void wl18xx_set_rx_csum(struct wl1271 *wl,
124862306a36Sopenharmony_ci			       struct wl1271_rx_descriptor *desc,
124962306a36Sopenharmony_ci			       struct sk_buff *skb)
125062306a36Sopenharmony_ci{
125162306a36Sopenharmony_ci	if (desc->status & WL18XX_RX_CHECKSUM_MASK)
125262306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic bool wl18xx_is_mimo_supported(struct wl1271 *wl)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct wl18xx_priv *priv = wl->priv;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/* only support MIMO with multiple antennas, and when SISO
126062306a36Sopenharmony_ci	 * is not forced through config
126162306a36Sopenharmony_ci	 */
126262306a36Sopenharmony_ci	return (priv->conf.phy.number_of_assembled_ant2_4 >= 2) &&
126362306a36Sopenharmony_ci	       (priv->conf.ht.mode != HT_MODE_WIDE) &&
126462306a36Sopenharmony_ci	       (priv->conf.ht.mode != HT_MODE_SISO20);
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci/*
126862306a36Sopenharmony_ci * TODO: instead of having these two functions to get the rate mask,
126962306a36Sopenharmony_ci * we should modify the wlvif->rate_set instead
127062306a36Sopenharmony_ci */
127162306a36Sopenharmony_cistatic u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl,
127262306a36Sopenharmony_ci				       struct wl12xx_vif *wlvif)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	u32 hw_rate_set = wlvif->rate_set;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
127762306a36Sopenharmony_ci	    wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
127862306a36Sopenharmony_ci		wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
127962306a36Sopenharmony_ci		hw_rate_set |= CONF_TX_RATE_USE_WIDE_CHAN;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci		/* we don't support MIMO in wide-channel mode */
128262306a36Sopenharmony_ci		hw_rate_set &= ~CONF_TX_MIMO_RATES;
128362306a36Sopenharmony_ci	} else if (wl18xx_is_mimo_supported(wl)) {
128462306a36Sopenharmony_ci		wl1271_debug(DEBUG_ACX, "using MIMO channel rate mask");
128562306a36Sopenharmony_ci		hw_rate_set |= CONF_TX_MIMO_RATES;
128662306a36Sopenharmony_ci	}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	return hw_rate_set;
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
129262306a36Sopenharmony_ci					     struct wl12xx_vif *wlvif)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	if (wlvif->channel_type == NL80211_CHAN_HT40MINUS ||
129562306a36Sopenharmony_ci	    wlvif->channel_type == NL80211_CHAN_HT40PLUS) {
129662306a36Sopenharmony_ci		wl1271_debug(DEBUG_ACX, "using wide channel rate mask");
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci		/* sanity check - we don't support this */
129962306a36Sopenharmony_ci		if (WARN_ON(wlvif->band != NL80211_BAND_5GHZ))
130062306a36Sopenharmony_ci			return 0;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci		return CONF_TX_RATE_USE_WIDE_CHAN;
130362306a36Sopenharmony_ci	} else if (wl18xx_is_mimo_supported(wl) &&
130462306a36Sopenharmony_ci		   wlvif->band == NL80211_BAND_2GHZ) {
130562306a36Sopenharmony_ci		wl1271_debug(DEBUG_ACX, "using MIMO rate mask");
130662306a36Sopenharmony_ci		/*
130762306a36Sopenharmony_ci		 * we don't care about HT channel here - if a peer doesn't
130862306a36Sopenharmony_ci		 * support MIMO, we won't enable it in its rates
130962306a36Sopenharmony_ci		 */
131062306a36Sopenharmony_ci		return CONF_TX_MIMO_RATES;
131162306a36Sopenharmony_ci	} else {
131262306a36Sopenharmony_ci		return 0;
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_cistatic const char *wl18xx_rdl_name(enum wl18xx_rdl_num rdl_num)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	switch (rdl_num) {
131962306a36Sopenharmony_ci	case RDL_1_HP:
132062306a36Sopenharmony_ci		return "183xH";
132162306a36Sopenharmony_ci	case RDL_2_SP:
132262306a36Sopenharmony_ci		return "183x or 180x";
132362306a36Sopenharmony_ci	case RDL_3_HP:
132462306a36Sopenharmony_ci		return "187xH";
132562306a36Sopenharmony_ci	case RDL_4_SP:
132662306a36Sopenharmony_ci		return "187x";
132762306a36Sopenharmony_ci	case RDL_5_SP:
132862306a36Sopenharmony_ci		return "RDL11 - Not Supported";
132962306a36Sopenharmony_ci	case RDL_6_SP:
133062306a36Sopenharmony_ci		return "180xD";
133162306a36Sopenharmony_ci	case RDL_7_SP:
133262306a36Sopenharmony_ci		return "RDL13 - Not Supported (1893Q)";
133362306a36Sopenharmony_ci	case RDL_8_SP:
133462306a36Sopenharmony_ci		return "18xxQ";
133562306a36Sopenharmony_ci	case RDL_NONE:
133662306a36Sopenharmony_ci		return "UNTRIMMED";
133762306a36Sopenharmony_ci	default:
133862306a36Sopenharmony_ci		return "UNKNOWN";
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	u32 fuse;
134562306a36Sopenharmony_ci	s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0, package_type = 0;
134662306a36Sopenharmony_ci	int ret;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
134962306a36Sopenharmony_ci	if (ret < 0)
135062306a36Sopenharmony_ci		goto out;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
135362306a36Sopenharmony_ci	if (ret < 0)
135462306a36Sopenharmony_ci		goto out;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	package_type = (fuse >> WL18XX_PACKAGE_TYPE_OFFSET) & 1;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
135962306a36Sopenharmony_ci	if (ret < 0)
136062306a36Sopenharmony_ci		goto out;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
136362306a36Sopenharmony_ci	rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	if ((rom <= 0xE) && (package_type == WL18XX_PACKAGE_TYPE_WSP))
136662306a36Sopenharmony_ci		metal = (fuse & WL18XX_METAL_VER_MASK) >>
136762306a36Sopenharmony_ci			WL18XX_METAL_VER_OFFSET;
136862306a36Sopenharmony_ci	else
136962306a36Sopenharmony_ci		metal = (fuse & WL18XX_NEW_METAL_VER_MASK) >>
137062306a36Sopenharmony_ci			WL18XX_NEW_METAL_VER_OFFSET;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
137362306a36Sopenharmony_ci	if (ret < 0)
137462306a36Sopenharmony_ci		goto out;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	wl1271_info("wl18xx HW: %s, PG %d.%d (ROM 0x%x)",
137962306a36Sopenharmony_ci		    wl18xx_rdl_name(rdl_ver), pg_ver, metal, rom);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	if (ver)
138262306a36Sopenharmony_ci		*ver = pg_ver;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ciout:
138762306a36Sopenharmony_ci	return ret;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic int wl18xx_load_conf_file(struct device *dev, struct wlcore_conf *conf,
139162306a36Sopenharmony_ci				 struct wl18xx_priv_conf *priv_conf,
139262306a36Sopenharmony_ci				 const char *file)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	struct wlcore_conf_file *conf_file;
139562306a36Sopenharmony_ci	const struct firmware *fw;
139662306a36Sopenharmony_ci	int ret;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	ret = request_firmware(&fw, file, dev);
139962306a36Sopenharmony_ci	if (ret < 0) {
140062306a36Sopenharmony_ci		wl1271_error("could not get configuration binary %s: %d",
140162306a36Sopenharmony_ci			     file, ret);
140262306a36Sopenharmony_ci		return ret;
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (fw->size != WL18XX_CONF_SIZE) {
140662306a36Sopenharmony_ci		wl1271_error("%s configuration binary size is wrong, expected %zu got %zu",
140762306a36Sopenharmony_ci			     file, WL18XX_CONF_SIZE, fw->size);
140862306a36Sopenharmony_ci		ret = -EINVAL;
140962306a36Sopenharmony_ci		goto out_release;
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	conf_file = (struct wlcore_conf_file *) fw->data;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	if (conf_file->header.magic != cpu_to_le32(WL18XX_CONF_MAGIC)) {
141562306a36Sopenharmony_ci		wl1271_error("configuration binary file magic number mismatch, "
141662306a36Sopenharmony_ci			     "expected 0x%0x got 0x%0x", WL18XX_CONF_MAGIC,
141762306a36Sopenharmony_ci			     conf_file->header.magic);
141862306a36Sopenharmony_ci		ret = -EINVAL;
141962306a36Sopenharmony_ci		goto out_release;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	if (conf_file->header.version != cpu_to_le32(WL18XX_CONF_VERSION)) {
142362306a36Sopenharmony_ci		wl1271_error("configuration binary file version not supported, "
142462306a36Sopenharmony_ci			     "expected 0x%08x got 0x%08x",
142562306a36Sopenharmony_ci			     WL18XX_CONF_VERSION, conf_file->header.version);
142662306a36Sopenharmony_ci		ret = -EINVAL;
142762306a36Sopenharmony_ci		goto out_release;
142862306a36Sopenharmony_ci	}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	memcpy(conf, &conf_file->core, sizeof(*conf));
143162306a36Sopenharmony_ci	memcpy(priv_conf, &conf_file->priv, sizeof(*priv_conf));
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ciout_release:
143462306a36Sopenharmony_ci	release_firmware(fw);
143562306a36Sopenharmony_ci	return ret;
143662306a36Sopenharmony_ci}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_cistatic int wl18xx_conf_init(struct wl1271 *wl, struct device *dev)
143962306a36Sopenharmony_ci{
144062306a36Sopenharmony_ci	struct platform_device *pdev = wl->pdev;
144162306a36Sopenharmony_ci	struct wlcore_platdev_data *pdata = dev_get_platdata(&pdev->dev);
144262306a36Sopenharmony_ci	struct wl18xx_priv *priv = wl->priv;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (wl18xx_load_conf_file(dev, &wl->conf, &priv->conf,
144562306a36Sopenharmony_ci				  pdata->family->cfg_name) < 0) {
144662306a36Sopenharmony_ci		wl1271_warning("falling back to default config");
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci		/* apply driver default configuration */
144962306a36Sopenharmony_ci		memcpy(&wl->conf, &wl18xx_conf, sizeof(wl->conf));
145062306a36Sopenharmony_ci		/* apply default private configuration */
145162306a36Sopenharmony_ci		memcpy(&priv->conf, &wl18xx_default_priv_conf,
145262306a36Sopenharmony_ci		       sizeof(priv->conf));
145362306a36Sopenharmony_ci	}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	return 0;
145662306a36Sopenharmony_ci}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_cistatic int wl18xx_plt_init(struct wl1271 *wl)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	int ret;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	/* calibrator based auto/fem detect not supported for 18xx */
146362306a36Sopenharmony_ci	if (wl->plt_mode == PLT_FEM_DETECT) {
146462306a36Sopenharmony_ci		wl1271_error("wl18xx_plt_init: PLT FEM_DETECT not supported");
146562306a36Sopenharmony_ci		return -EINVAL;
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	ret = wlcore_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT);
146962306a36Sopenharmony_ci	if (ret < 0)
147062306a36Sopenharmony_ci		return ret;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	return wl->ops->boot(wl);
147362306a36Sopenharmony_ci}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cistatic int wl18xx_get_mac(struct wl1271 *wl)
147662306a36Sopenharmony_ci{
147762306a36Sopenharmony_ci	u32 mac1, mac2;
147862306a36Sopenharmony_ci	int ret;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
148162306a36Sopenharmony_ci	if (ret < 0)
148262306a36Sopenharmony_ci		goto out;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1, &mac1);
148562306a36Sopenharmony_ci	if (ret < 0)
148662306a36Sopenharmony_ci		goto out;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2, &mac2);
148962306a36Sopenharmony_ci	if (ret < 0)
149062306a36Sopenharmony_ci		goto out;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	/* these are the two parts of the BD_ADDR */
149362306a36Sopenharmony_ci	wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
149462306a36Sopenharmony_ci		((mac1 & 0xff000000) >> 24);
149562306a36Sopenharmony_ci	wl->fuse_nic_addr = (mac1 & 0xffffff);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	if (!wl->fuse_oui_addr && !wl->fuse_nic_addr) {
149862306a36Sopenharmony_ci		u8 mac[ETH_ALEN];
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		eth_random_addr(mac);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci		wl->fuse_oui_addr = (mac[0] << 16) + (mac[1] << 8) + mac[2];
150362306a36Sopenharmony_ci		wl->fuse_nic_addr = (mac[3] << 16) + (mac[4] << 8) + mac[5];
150462306a36Sopenharmony_ci		wl1271_warning("MAC address from fuse not available, using random locally administered addresses.");
150562306a36Sopenharmony_ci	}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ciout:
151062306a36Sopenharmony_ci	return ret;
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cistatic int wl18xx_handle_static_data(struct wl1271 *wl,
151462306a36Sopenharmony_ci				     struct wl1271_static_data *static_data)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	struct wl18xx_static_data_priv *static_data_priv =
151762306a36Sopenharmony_ci		(struct wl18xx_static_data_priv *) static_data->priv;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	strncpy(wl->chip.phy_fw_ver_str, static_data_priv->phy_version,
152062306a36Sopenharmony_ci		sizeof(wl->chip.phy_fw_ver_str));
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	/* make sure the string is NULL-terminated */
152362306a36Sopenharmony_ci	wl->chip.phy_fw_ver_str[sizeof(wl->chip.phy_fw_ver_str) - 1] = '\0';
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	wl1271_info("PHY firmware version: %s", static_data_priv->phy_version);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	return 0;
152862306a36Sopenharmony_ci}
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_cistatic int wl18xx_get_spare_blocks(struct wl1271 *wl, bool is_gem)
153162306a36Sopenharmony_ci{
153262306a36Sopenharmony_ci	struct wl18xx_priv *priv = wl->priv;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	/* If we have keys requiring extra spare, indulge them */
153562306a36Sopenharmony_ci	if (priv->extra_spare_key_count)
153662306a36Sopenharmony_ci		return WL18XX_TX_HW_EXTRA_BLOCK_SPARE;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	return WL18XX_TX_HW_BLOCK_SPARE;
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_cistatic int wl18xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
154262306a36Sopenharmony_ci			  struct ieee80211_vif *vif,
154362306a36Sopenharmony_ci			  struct ieee80211_sta *sta,
154462306a36Sopenharmony_ci			  struct ieee80211_key_conf *key_conf)
154562306a36Sopenharmony_ci{
154662306a36Sopenharmony_ci	struct wl18xx_priv *priv = wl->priv;
154762306a36Sopenharmony_ci	bool change_spare = false, special_enc;
154862306a36Sopenharmony_ci	int ret;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	wl1271_debug(DEBUG_CRYPT, "extra spare keys before: %d",
155162306a36Sopenharmony_ci		     priv->extra_spare_key_count);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	special_enc = key_conf->cipher == WL1271_CIPHER_SUITE_GEM ||
155462306a36Sopenharmony_ci		      key_conf->cipher == WLAN_CIPHER_SUITE_TKIP;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	ret = wlcore_set_key(wl, cmd, vif, sta, key_conf);
155762306a36Sopenharmony_ci	if (ret < 0)
155862306a36Sopenharmony_ci		goto out;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	/*
156162306a36Sopenharmony_ci	 * when adding the first or removing the last GEM/TKIP key,
156262306a36Sopenharmony_ci	 * we have to adjust the number of spare blocks.
156362306a36Sopenharmony_ci	 */
156462306a36Sopenharmony_ci	if (special_enc) {
156562306a36Sopenharmony_ci		if (cmd == SET_KEY) {
156662306a36Sopenharmony_ci			/* first key */
156762306a36Sopenharmony_ci			change_spare = (priv->extra_spare_key_count == 0);
156862306a36Sopenharmony_ci			priv->extra_spare_key_count++;
156962306a36Sopenharmony_ci		} else if (cmd == DISABLE_KEY) {
157062306a36Sopenharmony_ci			/* last key */
157162306a36Sopenharmony_ci			change_spare = (priv->extra_spare_key_count == 1);
157262306a36Sopenharmony_ci			priv->extra_spare_key_count--;
157362306a36Sopenharmony_ci		}
157462306a36Sopenharmony_ci	}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	wl1271_debug(DEBUG_CRYPT, "extra spare keys after: %d",
157762306a36Sopenharmony_ci		     priv->extra_spare_key_count);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	if (!change_spare)
158062306a36Sopenharmony_ci		goto out;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	/* key is now set, change the spare blocks */
158362306a36Sopenharmony_ci	if (priv->extra_spare_key_count)
158462306a36Sopenharmony_ci		ret = wl18xx_set_host_cfg_bitmap(wl,
158562306a36Sopenharmony_ci					WL18XX_TX_HW_EXTRA_BLOCK_SPARE);
158662306a36Sopenharmony_ci	else
158762306a36Sopenharmony_ci		ret = wl18xx_set_host_cfg_bitmap(wl,
158862306a36Sopenharmony_ci					WL18XX_TX_HW_BLOCK_SPARE);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ciout:
159162306a36Sopenharmony_ci	return ret;
159262306a36Sopenharmony_ci}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_cistatic u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
159562306a36Sopenharmony_ci			       u32 buf_offset, u32 last_len)
159662306a36Sopenharmony_ci{
159762306a36Sopenharmony_ci	if (wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) {
159862306a36Sopenharmony_ci		struct wl1271_tx_hw_descr *last_desc;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci		/* get the last TX HW descriptor written to the aggr buf */
160162306a36Sopenharmony_ci		last_desc = (struct wl1271_tx_hw_descr *)(wl->aggr_buf +
160262306a36Sopenharmony_ci							buf_offset - last_len);
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci		/* the last frame is padded up to an SDIO block */
160562306a36Sopenharmony_ci		last_desc->wl18xx_mem.ctrl &= ~WL18XX_TX_CTRL_NOT_PADDED;
160662306a36Sopenharmony_ci		return ALIGN(buf_offset, WL12XX_BUS_BLOCK_SIZE);
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	/* no modifications */
161062306a36Sopenharmony_ci	return buf_offset;
161162306a36Sopenharmony_ci}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_cistatic void wl18xx_sta_rc_update(struct wl1271 *wl,
161462306a36Sopenharmony_ci				 struct wl12xx_vif *wlvif)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40;
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	/* sanity */
162162306a36Sopenharmony_ci	if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
162262306a36Sopenharmony_ci		return;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	/* ignore the change before association */
162562306a36Sopenharmony_ci	if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
162662306a36Sopenharmony_ci		return;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	/*
162962306a36Sopenharmony_ci	 * If we started out as wide, we can change the operation mode. If we
163062306a36Sopenharmony_ci	 * thought this was a 20mhz AP, we have to reconnect
163162306a36Sopenharmony_ci	 */
163262306a36Sopenharmony_ci	if (wlvif->sta.role_chan_type == NL80211_CHAN_HT40MINUS ||
163362306a36Sopenharmony_ci	    wlvif->sta.role_chan_type == NL80211_CHAN_HT40PLUS)
163462306a36Sopenharmony_ci		wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
163562306a36Sopenharmony_ci	else
163662306a36Sopenharmony_ci		ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_cistatic int wl18xx_set_peer_cap(struct wl1271 *wl,
164062306a36Sopenharmony_ci			       struct ieee80211_sta_ht_cap *ht_cap,
164162306a36Sopenharmony_ci			       bool allow_ht_operation,
164262306a36Sopenharmony_ci			       u32 rate_set, u8 hlid)
164362306a36Sopenharmony_ci{
164462306a36Sopenharmony_ci	return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation,
164562306a36Sopenharmony_ci				       rate_set, hlid);
164662306a36Sopenharmony_ci}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_cistatic bool wl18xx_lnk_high_prio(struct wl1271 *wl, u8 hlid,
164962306a36Sopenharmony_ci				 struct wl1271_link *lnk)
165062306a36Sopenharmony_ci{
165162306a36Sopenharmony_ci	u8 thold;
165262306a36Sopenharmony_ci	struct wl18xx_fw_status_priv *status_priv =
165362306a36Sopenharmony_ci		(struct wl18xx_fw_status_priv *)wl->fw_status->priv;
165462306a36Sopenharmony_ci	unsigned long suspend_bitmap;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	/* if we don't have the link map yet, assume they all low prio */
165762306a36Sopenharmony_ci	if (!status_priv)
165862306a36Sopenharmony_ci		return false;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	/* suspended links are never high priority */
166162306a36Sopenharmony_ci	suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
166262306a36Sopenharmony_ci	if (test_bit(hlid, &suspend_bitmap))
166362306a36Sopenharmony_ci		return false;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	/* the priority thresholds are taken from FW */
166662306a36Sopenharmony_ci	if (test_bit(hlid, &wl->fw_fast_lnk_map) &&
166762306a36Sopenharmony_ci	    !test_bit(hlid, &wl->ap_fw_ps_map))
166862306a36Sopenharmony_ci		thold = status_priv->tx_fast_link_prio_threshold;
166962306a36Sopenharmony_ci	else
167062306a36Sopenharmony_ci		thold = status_priv->tx_slow_link_prio_threshold;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	return lnk->allocated_pkts < thold;
167362306a36Sopenharmony_ci}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_cistatic bool wl18xx_lnk_low_prio(struct wl1271 *wl, u8 hlid,
167662306a36Sopenharmony_ci				struct wl1271_link *lnk)
167762306a36Sopenharmony_ci{
167862306a36Sopenharmony_ci	u8 thold;
167962306a36Sopenharmony_ci	struct wl18xx_fw_status_priv *status_priv =
168062306a36Sopenharmony_ci		(struct wl18xx_fw_status_priv *)wl->fw_status->priv;
168162306a36Sopenharmony_ci	unsigned long suspend_bitmap;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	/* if we don't have the link map yet, assume they all low prio */
168462306a36Sopenharmony_ci	if (!status_priv)
168562306a36Sopenharmony_ci		return true;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	suspend_bitmap = le32_to_cpu(status_priv->link_suspend_bitmap);
168862306a36Sopenharmony_ci	if (test_bit(hlid, &suspend_bitmap))
168962306a36Sopenharmony_ci		thold = status_priv->tx_suspend_threshold;
169062306a36Sopenharmony_ci	else if (test_bit(hlid, &wl->fw_fast_lnk_map) &&
169162306a36Sopenharmony_ci		 !test_bit(hlid, &wl->ap_fw_ps_map))
169262306a36Sopenharmony_ci		thold = status_priv->tx_fast_stop_threshold;
169362306a36Sopenharmony_ci	else
169462306a36Sopenharmony_ci		thold = status_priv->tx_slow_stop_threshold;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	return lnk->allocated_pkts < thold;
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_cistatic u32 wl18xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	return hwaddr & ~0x80000000;
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cistatic int wl18xx_setup(struct wl1271 *wl);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_cistatic struct wlcore_ops wl18xx_ops = {
170762306a36Sopenharmony_ci	.setup		= wl18xx_setup,
170862306a36Sopenharmony_ci	.identify_chip	= wl18xx_identify_chip,
170962306a36Sopenharmony_ci	.boot		= wl18xx_boot,
171062306a36Sopenharmony_ci	.plt_init	= wl18xx_plt_init,
171162306a36Sopenharmony_ci	.trigger_cmd	= wl18xx_trigger_cmd,
171262306a36Sopenharmony_ci	.ack_event	= wl18xx_ack_event,
171362306a36Sopenharmony_ci	.wait_for_event	= wl18xx_wait_for_event,
171462306a36Sopenharmony_ci	.process_mailbox_events = wl18xx_process_mailbox_events,
171562306a36Sopenharmony_ci	.calc_tx_blocks = wl18xx_calc_tx_blocks,
171662306a36Sopenharmony_ci	.set_tx_desc_blocks = wl18xx_set_tx_desc_blocks,
171762306a36Sopenharmony_ci	.set_tx_desc_data_len = wl18xx_set_tx_desc_data_len,
171862306a36Sopenharmony_ci	.get_rx_buf_align = wl18xx_get_rx_buf_align,
171962306a36Sopenharmony_ci	.get_rx_packet_len = wl18xx_get_rx_packet_len,
172062306a36Sopenharmony_ci	.tx_immediate_compl = wl18xx_tx_immediate_completion,
172162306a36Sopenharmony_ci	.tx_delayed_compl = NULL,
172262306a36Sopenharmony_ci	.hw_init	= wl18xx_hw_init,
172362306a36Sopenharmony_ci	.convert_fw_status = wl18xx_convert_fw_status,
172462306a36Sopenharmony_ci	.set_tx_desc_csum = wl18xx_set_tx_desc_csum,
172562306a36Sopenharmony_ci	.get_pg_ver	= wl18xx_get_pg_ver,
172662306a36Sopenharmony_ci	.set_rx_csum = wl18xx_set_rx_csum,
172762306a36Sopenharmony_ci	.sta_get_ap_rate_mask = wl18xx_sta_get_ap_rate_mask,
172862306a36Sopenharmony_ci	.ap_get_mimo_wide_rate_mask = wl18xx_ap_get_mimo_wide_rate_mask,
172962306a36Sopenharmony_ci	.get_mac	= wl18xx_get_mac,
173062306a36Sopenharmony_ci	.debugfs_init	= wl18xx_debugfs_add_files,
173162306a36Sopenharmony_ci	.scan_start	= wl18xx_scan_start,
173262306a36Sopenharmony_ci	.scan_stop	= wl18xx_scan_stop,
173362306a36Sopenharmony_ci	.sched_scan_start	= wl18xx_sched_scan_start,
173462306a36Sopenharmony_ci	.sched_scan_stop	= wl18xx_scan_sched_scan_stop,
173562306a36Sopenharmony_ci	.handle_static_data	= wl18xx_handle_static_data,
173662306a36Sopenharmony_ci	.get_spare_blocks = wl18xx_get_spare_blocks,
173762306a36Sopenharmony_ci	.set_key	= wl18xx_set_key,
173862306a36Sopenharmony_ci	.channel_switch	= wl18xx_cmd_channel_switch,
173962306a36Sopenharmony_ci	.pre_pkt_send	= wl18xx_pre_pkt_send,
174062306a36Sopenharmony_ci	.sta_rc_update	= wl18xx_sta_rc_update,
174162306a36Sopenharmony_ci	.set_peer_cap	= wl18xx_set_peer_cap,
174262306a36Sopenharmony_ci	.convert_hwaddr = wl18xx_convert_hwaddr,
174362306a36Sopenharmony_ci	.lnk_high_prio	= wl18xx_lnk_high_prio,
174462306a36Sopenharmony_ci	.lnk_low_prio	= wl18xx_lnk_low_prio,
174562306a36Sopenharmony_ci	.smart_config_start = wl18xx_cmd_smart_config_start,
174662306a36Sopenharmony_ci	.smart_config_stop  = wl18xx_cmd_smart_config_stop,
174762306a36Sopenharmony_ci	.smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
174862306a36Sopenharmony_ci	.interrupt_notify = wl18xx_acx_interrupt_notify_config,
174962306a36Sopenharmony_ci	.rx_ba_filter	= wl18xx_acx_rx_ba_filter,
175062306a36Sopenharmony_ci	.ap_sleep	= wl18xx_acx_ap_sleep,
175162306a36Sopenharmony_ci	.set_cac	= wl18xx_cmd_set_cac,
175262306a36Sopenharmony_ci	.dfs_master_restart	= wl18xx_cmd_dfs_master_restart,
175362306a36Sopenharmony_ci};
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci/* HT cap appropriate for wide channels in 2Ghz */
175662306a36Sopenharmony_cistatic struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = {
175762306a36Sopenharmony_ci	.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
175862306a36Sopenharmony_ci	       IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40 |
175962306a36Sopenharmony_ci	       IEEE80211_HT_CAP_GRN_FLD,
176062306a36Sopenharmony_ci	.ht_supported = true,
176162306a36Sopenharmony_ci	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
176262306a36Sopenharmony_ci	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
176362306a36Sopenharmony_ci	.mcs = {
176462306a36Sopenharmony_ci		.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
176562306a36Sopenharmony_ci		.rx_highest = cpu_to_le16(150),
176662306a36Sopenharmony_ci		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
176762306a36Sopenharmony_ci		},
176862306a36Sopenharmony_ci};
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci/* HT cap appropriate for wide channels in 5Ghz */
177162306a36Sopenharmony_cistatic struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = {
177262306a36Sopenharmony_ci	.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
177362306a36Sopenharmony_ci	       IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
177462306a36Sopenharmony_ci	       IEEE80211_HT_CAP_GRN_FLD,
177562306a36Sopenharmony_ci	.ht_supported = true,
177662306a36Sopenharmony_ci	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
177762306a36Sopenharmony_ci	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
177862306a36Sopenharmony_ci	.mcs = {
177962306a36Sopenharmony_ci		.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
178062306a36Sopenharmony_ci		.rx_highest = cpu_to_le16(150),
178162306a36Sopenharmony_ci		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
178262306a36Sopenharmony_ci		},
178362306a36Sopenharmony_ci};
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci/* HT cap appropriate for SISO 20 */
178662306a36Sopenharmony_cistatic struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = {
178762306a36Sopenharmony_ci	.cap = IEEE80211_HT_CAP_SGI_20 |
178862306a36Sopenharmony_ci	       IEEE80211_HT_CAP_GRN_FLD,
178962306a36Sopenharmony_ci	.ht_supported = true,
179062306a36Sopenharmony_ci	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
179162306a36Sopenharmony_ci	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
179262306a36Sopenharmony_ci	.mcs = {
179362306a36Sopenharmony_ci		.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
179462306a36Sopenharmony_ci		.rx_highest = cpu_to_le16(72),
179562306a36Sopenharmony_ci		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
179662306a36Sopenharmony_ci		},
179762306a36Sopenharmony_ci};
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci/* HT cap appropriate for MIMO rates in 20mhz channel */
180062306a36Sopenharmony_cistatic struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = {
180162306a36Sopenharmony_ci	.cap = IEEE80211_HT_CAP_SGI_20 |
180262306a36Sopenharmony_ci	       IEEE80211_HT_CAP_GRN_FLD,
180362306a36Sopenharmony_ci	.ht_supported = true,
180462306a36Sopenharmony_ci	.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K,
180562306a36Sopenharmony_ci	.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
180662306a36Sopenharmony_ci	.mcs = {
180762306a36Sopenharmony_ci		.rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, },
180862306a36Sopenharmony_ci		.rx_highest = cpu_to_le16(144),
180962306a36Sopenharmony_ci		.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
181062306a36Sopenharmony_ci		},
181162306a36Sopenharmony_ci};
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_cistatic const struct ieee80211_iface_limit wl18xx_iface_limits[] = {
181462306a36Sopenharmony_ci	{
181562306a36Sopenharmony_ci		.max = 2,
181662306a36Sopenharmony_ci		.types = BIT(NL80211_IFTYPE_STATION),
181762306a36Sopenharmony_ci	},
181862306a36Sopenharmony_ci	{
181962306a36Sopenharmony_ci		.max = 1,
182062306a36Sopenharmony_ci		.types =   BIT(NL80211_IFTYPE_AP)
182162306a36Sopenharmony_ci			 | BIT(NL80211_IFTYPE_P2P_GO)
182262306a36Sopenharmony_ci			 | BIT(NL80211_IFTYPE_P2P_CLIENT)
182362306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH
182462306a36Sopenharmony_ci			 | BIT(NL80211_IFTYPE_MESH_POINT)
182562306a36Sopenharmony_ci#endif
182662306a36Sopenharmony_ci	},
182762306a36Sopenharmony_ci	{
182862306a36Sopenharmony_ci		.max = 1,
182962306a36Sopenharmony_ci		.types = BIT(NL80211_IFTYPE_P2P_DEVICE),
183062306a36Sopenharmony_ci	},
183162306a36Sopenharmony_ci};
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_cistatic const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = {
183462306a36Sopenharmony_ci	{
183562306a36Sopenharmony_ci		.max = 2,
183662306a36Sopenharmony_ci		.types = BIT(NL80211_IFTYPE_AP),
183762306a36Sopenharmony_ci	},
183862306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH
183962306a36Sopenharmony_ci	{
184062306a36Sopenharmony_ci		.max = 1,
184162306a36Sopenharmony_ci		.types = BIT(NL80211_IFTYPE_MESH_POINT),
184262306a36Sopenharmony_ci	},
184362306a36Sopenharmony_ci#endif
184462306a36Sopenharmony_ci	{
184562306a36Sopenharmony_ci		.max = 1,
184662306a36Sopenharmony_ci		.types = BIT(NL80211_IFTYPE_P2P_DEVICE),
184762306a36Sopenharmony_ci	},
184862306a36Sopenharmony_ci};
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_cistatic const struct ieee80211_iface_combination
185162306a36Sopenharmony_ciwl18xx_iface_combinations[] = {
185262306a36Sopenharmony_ci	{
185362306a36Sopenharmony_ci		.max_interfaces = 3,
185462306a36Sopenharmony_ci		.limits = wl18xx_iface_limits,
185562306a36Sopenharmony_ci		.n_limits = ARRAY_SIZE(wl18xx_iface_limits),
185662306a36Sopenharmony_ci		.num_different_channels = 2,
185762306a36Sopenharmony_ci	},
185862306a36Sopenharmony_ci	{
185962306a36Sopenharmony_ci		.max_interfaces = 2,
186062306a36Sopenharmony_ci		.limits = wl18xx_iface_ap_limits,
186162306a36Sopenharmony_ci		.n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits),
186262306a36Sopenharmony_ci		.num_different_channels = 1,
186362306a36Sopenharmony_ci		.radar_detect_widths =	BIT(NL80211_CHAN_NO_HT) |
186462306a36Sopenharmony_ci					BIT(NL80211_CHAN_HT20) |
186562306a36Sopenharmony_ci					BIT(NL80211_CHAN_HT40MINUS) |
186662306a36Sopenharmony_ci					BIT(NL80211_CHAN_HT40PLUS),
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci};
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_cistatic int wl18xx_setup(struct wl1271 *wl)
187162306a36Sopenharmony_ci{
187262306a36Sopenharmony_ci	struct wl18xx_priv *priv = wl->priv;
187362306a36Sopenharmony_ci	int ret;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	BUILD_BUG_ON(WL18XX_MAX_LINKS > WLCORE_MAX_LINKS);
187662306a36Sopenharmony_ci	BUILD_BUG_ON(WL18XX_MAX_AP_STATIONS > WL18XX_MAX_LINKS);
187762306a36Sopenharmony_ci	BUILD_BUG_ON(WL18XX_CONF_SG_PARAMS_MAX > WLCORE_CONF_SG_PARAMS_MAX);
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	wl->rtable = wl18xx_rtable;
188062306a36Sopenharmony_ci	wl->num_tx_desc = WL18XX_NUM_TX_DESCRIPTORS;
188162306a36Sopenharmony_ci	wl->num_rx_desc = WL18XX_NUM_RX_DESCRIPTORS;
188262306a36Sopenharmony_ci	wl->num_links = WL18XX_MAX_LINKS;
188362306a36Sopenharmony_ci	wl->max_ap_stations = WL18XX_MAX_AP_STATIONS;
188462306a36Sopenharmony_ci	wl->iface_combinations = wl18xx_iface_combinations;
188562306a36Sopenharmony_ci	wl->n_iface_combinations = ARRAY_SIZE(wl18xx_iface_combinations);
188662306a36Sopenharmony_ci	wl->num_mac_addr = WL18XX_NUM_MAC_ADDRESSES;
188762306a36Sopenharmony_ci	wl->band_rate_to_idx = wl18xx_band_rate_to_idx;
188862306a36Sopenharmony_ci	wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX;
188962306a36Sopenharmony_ci	wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0;
189062306a36Sopenharmony_ci	wl->fw_status_len = sizeof(struct wl18xx_fw_status);
189162306a36Sopenharmony_ci	wl->fw_status_priv_len = sizeof(struct wl18xx_fw_status_priv);
189262306a36Sopenharmony_ci	wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics);
189362306a36Sopenharmony_ci	wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv);
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	if (num_rx_desc_param != -1)
189662306a36Sopenharmony_ci		wl->num_rx_desc = num_rx_desc_param;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	ret = wl18xx_conf_init(wl, wl->dev);
189962306a36Sopenharmony_ci	if (ret < 0)
190062306a36Sopenharmony_ci		return ret;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	/* If the module param is set, update it in conf */
190362306a36Sopenharmony_ci	if (board_type_param) {
190462306a36Sopenharmony_ci		if (!strcmp(board_type_param, "fpga")) {
190562306a36Sopenharmony_ci			priv->conf.phy.board_type = BOARD_TYPE_FPGA_18XX;
190662306a36Sopenharmony_ci		} else if (!strcmp(board_type_param, "hdk")) {
190762306a36Sopenharmony_ci			priv->conf.phy.board_type = BOARD_TYPE_HDK_18XX;
190862306a36Sopenharmony_ci		} else if (!strcmp(board_type_param, "dvp")) {
190962306a36Sopenharmony_ci			priv->conf.phy.board_type = BOARD_TYPE_DVP_18XX;
191062306a36Sopenharmony_ci		} else if (!strcmp(board_type_param, "evb")) {
191162306a36Sopenharmony_ci			priv->conf.phy.board_type = BOARD_TYPE_EVB_18XX;
191262306a36Sopenharmony_ci		} else if (!strcmp(board_type_param, "com8")) {
191362306a36Sopenharmony_ci			priv->conf.phy.board_type = BOARD_TYPE_COM8_18XX;
191462306a36Sopenharmony_ci		} else {
191562306a36Sopenharmony_ci			wl1271_error("invalid board type '%s'",
191662306a36Sopenharmony_ci				board_type_param);
191762306a36Sopenharmony_ci			return -EINVAL;
191862306a36Sopenharmony_ci		}
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	if (priv->conf.phy.board_type >= NUM_BOARD_TYPES) {
192262306a36Sopenharmony_ci		wl1271_error("invalid board type '%d'",
192362306a36Sopenharmony_ci			priv->conf.phy.board_type);
192462306a36Sopenharmony_ci		return -EINVAL;
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	if (low_band_component_param != -1)
192862306a36Sopenharmony_ci		priv->conf.phy.low_band_component = low_band_component_param;
192962306a36Sopenharmony_ci	if (low_band_component_type_param != -1)
193062306a36Sopenharmony_ci		priv->conf.phy.low_band_component_type =
193162306a36Sopenharmony_ci			low_band_component_type_param;
193262306a36Sopenharmony_ci	if (high_band_component_param != -1)
193362306a36Sopenharmony_ci		priv->conf.phy.high_band_component = high_band_component_param;
193462306a36Sopenharmony_ci	if (high_band_component_type_param != -1)
193562306a36Sopenharmony_ci		priv->conf.phy.high_band_component_type =
193662306a36Sopenharmony_ci			high_band_component_type_param;
193762306a36Sopenharmony_ci	if (pwr_limit_reference_11_abg_param != -1)
193862306a36Sopenharmony_ci		priv->conf.phy.pwr_limit_reference_11_abg =
193962306a36Sopenharmony_ci			pwr_limit_reference_11_abg_param;
194062306a36Sopenharmony_ci	if (n_antennas_2_param != -1)
194162306a36Sopenharmony_ci		priv->conf.phy.number_of_assembled_ant2_4 = n_antennas_2_param;
194262306a36Sopenharmony_ci	if (n_antennas_5_param != -1)
194362306a36Sopenharmony_ci		priv->conf.phy.number_of_assembled_ant5 = n_antennas_5_param;
194462306a36Sopenharmony_ci	if (dc2dc_param != -1)
194562306a36Sopenharmony_ci		priv->conf.phy.external_pa_dc2dc = dc2dc_param;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	if (ht_mode_param) {
194862306a36Sopenharmony_ci		if (!strcmp(ht_mode_param, "default"))
194962306a36Sopenharmony_ci			priv->conf.ht.mode = HT_MODE_DEFAULT;
195062306a36Sopenharmony_ci		else if (!strcmp(ht_mode_param, "wide"))
195162306a36Sopenharmony_ci			priv->conf.ht.mode = HT_MODE_WIDE;
195262306a36Sopenharmony_ci		else if (!strcmp(ht_mode_param, "siso20"))
195362306a36Sopenharmony_ci			priv->conf.ht.mode = HT_MODE_SISO20;
195462306a36Sopenharmony_ci		else {
195562306a36Sopenharmony_ci			wl1271_error("invalid ht_mode '%s'", ht_mode_param);
195662306a36Sopenharmony_ci			return -EINVAL;
195762306a36Sopenharmony_ci		}
195862306a36Sopenharmony_ci	}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	if (priv->conf.ht.mode == HT_MODE_DEFAULT) {
196162306a36Sopenharmony_ci		/*
196262306a36Sopenharmony_ci		 * Only support mimo with multiple antennas. Fall back to
196362306a36Sopenharmony_ci		 * siso40.
196462306a36Sopenharmony_ci		 */
196562306a36Sopenharmony_ci		if (wl18xx_is_mimo_supported(wl))
196662306a36Sopenharmony_ci			wlcore_set_ht_cap(wl, NL80211_BAND_2GHZ,
196762306a36Sopenharmony_ci					  &wl18xx_mimo_ht_cap_2ghz);
196862306a36Sopenharmony_ci		else
196962306a36Sopenharmony_ci			wlcore_set_ht_cap(wl, NL80211_BAND_2GHZ,
197062306a36Sopenharmony_ci					  &wl18xx_siso40_ht_cap_2ghz);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci		/* 5Ghz is always wide */
197362306a36Sopenharmony_ci		wlcore_set_ht_cap(wl, NL80211_BAND_5GHZ,
197462306a36Sopenharmony_ci				  &wl18xx_siso40_ht_cap_5ghz);
197562306a36Sopenharmony_ci	} else if (priv->conf.ht.mode == HT_MODE_WIDE) {
197662306a36Sopenharmony_ci		wlcore_set_ht_cap(wl, NL80211_BAND_2GHZ,
197762306a36Sopenharmony_ci				  &wl18xx_siso40_ht_cap_2ghz);
197862306a36Sopenharmony_ci		wlcore_set_ht_cap(wl, NL80211_BAND_5GHZ,
197962306a36Sopenharmony_ci				  &wl18xx_siso40_ht_cap_5ghz);
198062306a36Sopenharmony_ci	} else if (priv->conf.ht.mode == HT_MODE_SISO20) {
198162306a36Sopenharmony_ci		wlcore_set_ht_cap(wl, NL80211_BAND_2GHZ,
198262306a36Sopenharmony_ci				  &wl18xx_siso20_ht_cap);
198362306a36Sopenharmony_ci		wlcore_set_ht_cap(wl, NL80211_BAND_5GHZ,
198462306a36Sopenharmony_ci				  &wl18xx_siso20_ht_cap);
198562306a36Sopenharmony_ci	}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	if (!checksum_param) {
198862306a36Sopenharmony_ci		wl18xx_ops.set_rx_csum = NULL;
198962306a36Sopenharmony_ci		wl18xx_ops.init_vif = NULL;
199062306a36Sopenharmony_ci	}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	/* Enable 11a Band only if we have 5G antennas */
199362306a36Sopenharmony_ci	wl->enable_11a = (priv->conf.phy.number_of_assembled_ant5 != 0);
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	return 0;
199662306a36Sopenharmony_ci}
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_cistatic int wl18xx_probe(struct platform_device *pdev)
199962306a36Sopenharmony_ci{
200062306a36Sopenharmony_ci	struct wl1271 *wl;
200162306a36Sopenharmony_ci	struct ieee80211_hw *hw;
200262306a36Sopenharmony_ci	int ret;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	hw = wlcore_alloc_hw(sizeof(struct wl18xx_priv),
200562306a36Sopenharmony_ci			     WL18XX_AGGR_BUFFER_SIZE,
200662306a36Sopenharmony_ci			     sizeof(struct wl18xx_event_mailbox));
200762306a36Sopenharmony_ci	if (IS_ERR(hw)) {
200862306a36Sopenharmony_ci		wl1271_error("can't allocate hw");
200962306a36Sopenharmony_ci		ret = PTR_ERR(hw);
201062306a36Sopenharmony_ci		goto out;
201162306a36Sopenharmony_ci	}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	wl = hw->priv;
201462306a36Sopenharmony_ci	wl->ops = &wl18xx_ops;
201562306a36Sopenharmony_ci	wl->ptable = wl18xx_ptable;
201662306a36Sopenharmony_ci	ret = wlcore_probe(wl, pdev);
201762306a36Sopenharmony_ci	if (ret)
201862306a36Sopenharmony_ci		goto out_free;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	return ret;
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ciout_free:
202362306a36Sopenharmony_ci	wlcore_free_hw(wl);
202462306a36Sopenharmony_ciout:
202562306a36Sopenharmony_ci	return ret;
202662306a36Sopenharmony_ci}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_cistatic const struct platform_device_id wl18xx_id_table[] = {
202962306a36Sopenharmony_ci	{ "wl18xx", 0 },
203062306a36Sopenharmony_ci	{  } /* Terminating Entry */
203162306a36Sopenharmony_ci};
203262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, wl18xx_id_table);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_cistatic struct platform_driver wl18xx_driver = {
203562306a36Sopenharmony_ci	.probe		= wl18xx_probe,
203662306a36Sopenharmony_ci	.remove		= wlcore_remove,
203762306a36Sopenharmony_ci	.id_table	= wl18xx_id_table,
203862306a36Sopenharmony_ci	.driver = {
203962306a36Sopenharmony_ci		.name	= "wl18xx_driver",
204062306a36Sopenharmony_ci	}
204162306a36Sopenharmony_ci};
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_cimodule_platform_driver(wl18xx_driver);
204462306a36Sopenharmony_cimodule_param_named(ht_mode, ht_mode_param, charp, 0400);
204562306a36Sopenharmony_ciMODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20");
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_cimodule_param_named(board_type, board_type_param, charp, 0400);
204862306a36Sopenharmony_ciMODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or "
204962306a36Sopenharmony_ci		 "dvp");
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_cimodule_param_named(checksum, checksum_param, bool, 0400);
205262306a36Sopenharmony_ciMODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)");
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_cimodule_param_named(dc2dc, dc2dc_param, int, 0400);
205562306a36Sopenharmony_ciMODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)");
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_cimodule_param_named(n_antennas_2, n_antennas_2_param, int, 0400);
205862306a36Sopenharmony_ciMODULE_PARM_DESC(n_antennas_2,
205962306a36Sopenharmony_ci		 "Number of installed 2.4GHz antennas: 1 (default) or 2");
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_cimodule_param_named(n_antennas_5, n_antennas_5_param, int, 0400);
206262306a36Sopenharmony_ciMODULE_PARM_DESC(n_antennas_5,
206362306a36Sopenharmony_ci		 "Number of installed 5GHz antennas: 1 (default) or 2");
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_cimodule_param_named(low_band_component, low_band_component_param, int, 0400);
206662306a36Sopenharmony_ciMODULE_PARM_DESC(low_band_component, "Low band component: u8 "
206762306a36Sopenharmony_ci		 "(default is 0x01)");
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_cimodule_param_named(low_band_component_type, low_band_component_type_param,
207062306a36Sopenharmony_ci		   int, 0400);
207162306a36Sopenharmony_ciMODULE_PARM_DESC(low_band_component_type, "Low band component type: u8 "
207262306a36Sopenharmony_ci		 "(default is 0x05 or 0x06 depending on the board_type)");
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_cimodule_param_named(high_band_component, high_band_component_param, int, 0400);
207562306a36Sopenharmony_ciMODULE_PARM_DESC(high_band_component, "High band component: u8, "
207662306a36Sopenharmony_ci		 "(default is 0x01)");
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cimodule_param_named(high_band_component_type, high_band_component_type_param,
207962306a36Sopenharmony_ci		   int, 0400);
208062306a36Sopenharmony_ciMODULE_PARM_DESC(high_band_component_type, "High band component type: u8 "
208162306a36Sopenharmony_ci		 "(default is 0x09)");
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cimodule_param_named(pwr_limit_reference_11_abg,
208462306a36Sopenharmony_ci		   pwr_limit_reference_11_abg_param, int, 0400);
208562306a36Sopenharmony_ciMODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 "
208662306a36Sopenharmony_ci		 "(default is 0xc8)");
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_cimodule_param_named(num_rx_desc, num_rx_desc_param, int, 0400);
208962306a36Sopenharmony_ciMODULE_PARM_DESC(num_rx_desc_param,
209062306a36Sopenharmony_ci		 "Number of Rx descriptors: u8 (default is 32)");
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
209362306a36Sopenharmony_ciMODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
209462306a36Sopenharmony_ciMODULE_FIRMWARE(WL18XX_FW_NAME);
2095