162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file is part of wl1271 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008-2010 Nokia Corporation 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 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "../wlcore/wlcore.h" 1562306a36Sopenharmony_ci#include "../wlcore/debug.h" 1662306a36Sopenharmony_ci#include "../wlcore/io.h" 1762306a36Sopenharmony_ci#include "../wlcore/acx.h" 1862306a36Sopenharmony_ci#include "../wlcore/tx.h" 1962306a36Sopenharmony_ci#include "../wlcore/rx.h" 2062306a36Sopenharmony_ci#include "../wlcore/boot.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "wl12xx.h" 2362306a36Sopenharmony_ci#include "reg.h" 2462306a36Sopenharmony_ci#include "cmd.h" 2562306a36Sopenharmony_ci#include "acx.h" 2662306a36Sopenharmony_ci#include "scan.h" 2762306a36Sopenharmony_ci#include "event.h" 2862306a36Sopenharmony_ci#include "debugfs.h" 2962306a36Sopenharmony_ci#include "conf.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic char *fref_param; 3262306a36Sopenharmony_cistatic char *tcxo_param; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic struct wlcore_conf wl12xx_conf = { 3562306a36Sopenharmony_ci .sg = { 3662306a36Sopenharmony_ci .params = { 3762306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, 3862306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, 3962306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, 4062306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, 4162306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, 4262306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, 4362306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, 4462306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, 4562306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, 4662306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, 4762306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, 4862306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, 4962306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, 5062306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, 5162306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, 5262306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, 5362306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, 5462306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, 5562306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, 5662306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, 5762306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, 5862306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, 5962306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, 6062306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, 6162306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, 6262306a36Sopenharmony_ci [WL12XX_CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, 6362306a36Sopenharmony_ci /* active scan params */ 6462306a36Sopenharmony_ci [WL12XX_CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, 6562306a36Sopenharmony_ci [WL12XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, 6662306a36Sopenharmony_ci [WL12XX_CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, 6762306a36Sopenharmony_ci /* passive scan params */ 6862306a36Sopenharmony_ci [WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_A2DP_BR] = 800, 6962306a36Sopenharmony_ci [WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_A2DP_EDR] = 200, 7062306a36Sopenharmony_ci [WL12XX_CONF_SG_PASSIVE_SCAN_DUR_FACTOR_HV3] = 200, 7162306a36Sopenharmony_ci /* passive scan in dual antenna params */ 7262306a36Sopenharmony_ci [WL12XX_CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, 7362306a36Sopenharmony_ci [WL12XX_CONF_SG_BCN_HV3_COLL_THR_IN_PASSIVE_SCAN] = 0, 7462306a36Sopenharmony_ci [WL12XX_CONF_SG_TX_RX_PROTECT_BW_IN_PASSIVE_SCAN] = 0, 7562306a36Sopenharmony_ci /* general params */ 7662306a36Sopenharmony_ci [WL12XX_CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, 7762306a36Sopenharmony_ci [WL12XX_CONF_SG_ANTENNA_CONFIGURATION] = 0, 7862306a36Sopenharmony_ci [WL12XX_CONF_SG_BEACON_MISS_PERCENT] = 60, 7962306a36Sopenharmony_ci [WL12XX_CONF_SG_DHCP_TIME] = 5000, 8062306a36Sopenharmony_ci [WL12XX_CONF_SG_RXT] = 1200, 8162306a36Sopenharmony_ci [WL12XX_CONF_SG_TXT] = 1000, 8262306a36Sopenharmony_ci [WL12XX_CONF_SG_ADAPTIVE_RXT_TXT] = 1, 8362306a36Sopenharmony_ci [WL12XX_CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, 8462306a36Sopenharmony_ci [WL12XX_CONF_SG_HV3_MAX_SERVED] = 6, 8562306a36Sopenharmony_ci [WL12XX_CONF_SG_PS_POLL_TIMEOUT] = 10, 8662306a36Sopenharmony_ci [WL12XX_CONF_SG_UPSD_TIMEOUT] = 10, 8762306a36Sopenharmony_ci [WL12XX_CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, 8862306a36Sopenharmony_ci [WL12XX_CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, 8962306a36Sopenharmony_ci [WL12XX_CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, 9062306a36Sopenharmony_ci /* AP params */ 9162306a36Sopenharmony_ci [WL12XX_CONF_AP_BEACON_MISS_TX] = 3, 9262306a36Sopenharmony_ci [WL12XX_CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, 9362306a36Sopenharmony_ci [WL12XX_CONF_AP_BEACON_WINDOW_INTERVAL] = 2, 9462306a36Sopenharmony_ci [WL12XX_CONF_AP_CONNECTION_PROTECTION_TIME] = 0, 9562306a36Sopenharmony_ci [WL12XX_CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, 9662306a36Sopenharmony_ci [WL12XX_CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, 9762306a36Sopenharmony_ci /* CTS Diluting params */ 9862306a36Sopenharmony_ci [WL12XX_CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0, 9962306a36Sopenharmony_ci [WL12XX_CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0, 10062306a36Sopenharmony_ci }, 10162306a36Sopenharmony_ci .state = CONF_SG_PROTECTIVE, 10262306a36Sopenharmony_ci }, 10362306a36Sopenharmony_ci .rx = { 10462306a36Sopenharmony_ci .rx_msdu_life_time = 512000, 10562306a36Sopenharmony_ci .packet_detection_threshold = 0, 10662306a36Sopenharmony_ci .ps_poll_timeout = 15, 10762306a36Sopenharmony_ci .upsd_timeout = 15, 10862306a36Sopenharmony_ci .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, 10962306a36Sopenharmony_ci .rx_cca_threshold = 0, 11062306a36Sopenharmony_ci .irq_blk_threshold = 0xFFFF, 11162306a36Sopenharmony_ci .irq_pkt_threshold = 0, 11262306a36Sopenharmony_ci .irq_timeout = 600, 11362306a36Sopenharmony_ci .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, 11462306a36Sopenharmony_ci }, 11562306a36Sopenharmony_ci .tx = { 11662306a36Sopenharmony_ci .tx_energy_detection = 0, 11762306a36Sopenharmony_ci .sta_rc_conf = { 11862306a36Sopenharmony_ci .enabled_rates = 0, 11962306a36Sopenharmony_ci .short_retry_limit = 10, 12062306a36Sopenharmony_ci .long_retry_limit = 10, 12162306a36Sopenharmony_ci .aflags = 0, 12262306a36Sopenharmony_ci }, 12362306a36Sopenharmony_ci .ac_conf_count = 4, 12462306a36Sopenharmony_ci .ac_conf = { 12562306a36Sopenharmony_ci [CONF_TX_AC_BE] = { 12662306a36Sopenharmony_ci .ac = CONF_TX_AC_BE, 12762306a36Sopenharmony_ci .cw_min = 15, 12862306a36Sopenharmony_ci .cw_max = 63, 12962306a36Sopenharmony_ci .aifsn = 3, 13062306a36Sopenharmony_ci .tx_op_limit = 0, 13162306a36Sopenharmony_ci }, 13262306a36Sopenharmony_ci [CONF_TX_AC_BK] = { 13362306a36Sopenharmony_ci .ac = CONF_TX_AC_BK, 13462306a36Sopenharmony_ci .cw_min = 15, 13562306a36Sopenharmony_ci .cw_max = 63, 13662306a36Sopenharmony_ci .aifsn = 7, 13762306a36Sopenharmony_ci .tx_op_limit = 0, 13862306a36Sopenharmony_ci }, 13962306a36Sopenharmony_ci [CONF_TX_AC_VI] = { 14062306a36Sopenharmony_ci .ac = CONF_TX_AC_VI, 14162306a36Sopenharmony_ci .cw_min = 15, 14262306a36Sopenharmony_ci .cw_max = 63, 14362306a36Sopenharmony_ci .aifsn = CONF_TX_AIFS_PIFS, 14462306a36Sopenharmony_ci .tx_op_limit = 3008, 14562306a36Sopenharmony_ci }, 14662306a36Sopenharmony_ci [CONF_TX_AC_VO] = { 14762306a36Sopenharmony_ci .ac = CONF_TX_AC_VO, 14862306a36Sopenharmony_ci .cw_min = 15, 14962306a36Sopenharmony_ci .cw_max = 63, 15062306a36Sopenharmony_ci .aifsn = CONF_TX_AIFS_PIFS, 15162306a36Sopenharmony_ci .tx_op_limit = 1504, 15262306a36Sopenharmony_ci }, 15362306a36Sopenharmony_ci }, 15462306a36Sopenharmony_ci .max_tx_retries = 100, 15562306a36Sopenharmony_ci .ap_aging_period = 300, 15662306a36Sopenharmony_ci .tid_conf_count = 4, 15762306a36Sopenharmony_ci .tid_conf = { 15862306a36Sopenharmony_ci [CONF_TX_AC_BE] = { 15962306a36Sopenharmony_ci .queue_id = CONF_TX_AC_BE, 16062306a36Sopenharmony_ci .channel_type = CONF_CHANNEL_TYPE_EDCF, 16162306a36Sopenharmony_ci .tsid = CONF_TX_AC_BE, 16262306a36Sopenharmony_ci .ps_scheme = CONF_PS_SCHEME_LEGACY, 16362306a36Sopenharmony_ci .ack_policy = CONF_ACK_POLICY_LEGACY, 16462306a36Sopenharmony_ci .apsd_conf = {0, 0}, 16562306a36Sopenharmony_ci }, 16662306a36Sopenharmony_ci [CONF_TX_AC_BK] = { 16762306a36Sopenharmony_ci .queue_id = CONF_TX_AC_BK, 16862306a36Sopenharmony_ci .channel_type = CONF_CHANNEL_TYPE_EDCF, 16962306a36Sopenharmony_ci .tsid = CONF_TX_AC_BK, 17062306a36Sopenharmony_ci .ps_scheme = CONF_PS_SCHEME_LEGACY, 17162306a36Sopenharmony_ci .ack_policy = CONF_ACK_POLICY_LEGACY, 17262306a36Sopenharmony_ci .apsd_conf = {0, 0}, 17362306a36Sopenharmony_ci }, 17462306a36Sopenharmony_ci [CONF_TX_AC_VI] = { 17562306a36Sopenharmony_ci .queue_id = CONF_TX_AC_VI, 17662306a36Sopenharmony_ci .channel_type = CONF_CHANNEL_TYPE_EDCF, 17762306a36Sopenharmony_ci .tsid = CONF_TX_AC_VI, 17862306a36Sopenharmony_ci .ps_scheme = CONF_PS_SCHEME_LEGACY, 17962306a36Sopenharmony_ci .ack_policy = CONF_ACK_POLICY_LEGACY, 18062306a36Sopenharmony_ci .apsd_conf = {0, 0}, 18162306a36Sopenharmony_ci }, 18262306a36Sopenharmony_ci [CONF_TX_AC_VO] = { 18362306a36Sopenharmony_ci .queue_id = CONF_TX_AC_VO, 18462306a36Sopenharmony_ci .channel_type = CONF_CHANNEL_TYPE_EDCF, 18562306a36Sopenharmony_ci .tsid = CONF_TX_AC_VO, 18662306a36Sopenharmony_ci .ps_scheme = CONF_PS_SCHEME_LEGACY, 18762306a36Sopenharmony_ci .ack_policy = CONF_ACK_POLICY_LEGACY, 18862306a36Sopenharmony_ci .apsd_conf = {0, 0}, 18962306a36Sopenharmony_ci }, 19062306a36Sopenharmony_ci }, 19162306a36Sopenharmony_ci .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, 19262306a36Sopenharmony_ci .tx_compl_timeout = 700, 19362306a36Sopenharmony_ci .tx_compl_threshold = 4, 19462306a36Sopenharmony_ci .basic_rate = CONF_HW_BIT_RATE_1MBPS, 19562306a36Sopenharmony_ci .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS, 19662306a36Sopenharmony_ci .tmpl_short_retry_limit = 10, 19762306a36Sopenharmony_ci .tmpl_long_retry_limit = 10, 19862306a36Sopenharmony_ci .tx_watchdog_timeout = 5000, 19962306a36Sopenharmony_ci .slow_link_thold = 3, 20062306a36Sopenharmony_ci .fast_link_thold = 10, 20162306a36Sopenharmony_ci }, 20262306a36Sopenharmony_ci .conn = { 20362306a36Sopenharmony_ci .wake_up_event = CONF_WAKE_UP_EVENT_DTIM, 20462306a36Sopenharmony_ci .listen_interval = 1, 20562306a36Sopenharmony_ci .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM, 20662306a36Sopenharmony_ci .suspend_listen_interval = 3, 20762306a36Sopenharmony_ci .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED, 20862306a36Sopenharmony_ci .bcn_filt_ie_count = 3, 20962306a36Sopenharmony_ci .bcn_filt_ie = { 21062306a36Sopenharmony_ci [0] = { 21162306a36Sopenharmony_ci .ie = WLAN_EID_CHANNEL_SWITCH, 21262306a36Sopenharmony_ci .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE, 21362306a36Sopenharmony_ci }, 21462306a36Sopenharmony_ci [1] = { 21562306a36Sopenharmony_ci .ie = WLAN_EID_HT_OPERATION, 21662306a36Sopenharmony_ci .rule = CONF_BCN_RULE_PASS_ON_CHANGE, 21762306a36Sopenharmony_ci }, 21862306a36Sopenharmony_ci [2] = { 21962306a36Sopenharmony_ci .ie = WLAN_EID_ERP_INFO, 22062306a36Sopenharmony_ci .rule = CONF_BCN_RULE_PASS_ON_CHANGE, 22162306a36Sopenharmony_ci }, 22262306a36Sopenharmony_ci }, 22362306a36Sopenharmony_ci .synch_fail_thold = 12, 22462306a36Sopenharmony_ci .bss_lose_timeout = 400, 22562306a36Sopenharmony_ci .beacon_rx_timeout = 10000, 22662306a36Sopenharmony_ci .broadcast_timeout = 20000, 22762306a36Sopenharmony_ci .rx_broadcast_in_ps = 1, 22862306a36Sopenharmony_ci .ps_poll_threshold = 10, 22962306a36Sopenharmony_ci .bet_enable = CONF_BET_MODE_ENABLE, 23062306a36Sopenharmony_ci .bet_max_consecutive = 50, 23162306a36Sopenharmony_ci .psm_entry_retries = 8, 23262306a36Sopenharmony_ci .psm_exit_retries = 16, 23362306a36Sopenharmony_ci .psm_entry_nullfunc_retries = 3, 23462306a36Sopenharmony_ci .dynamic_ps_timeout = 1500, 23562306a36Sopenharmony_ci .forced_ps = false, 23662306a36Sopenharmony_ci .keep_alive_interval = 55000, 23762306a36Sopenharmony_ci .max_listen_interval = 20, 23862306a36Sopenharmony_ci .sta_sleep_auth = WL1271_PSM_ILLEGAL, 23962306a36Sopenharmony_ci .suspend_rx_ba_activity = 0, 24062306a36Sopenharmony_ci }, 24162306a36Sopenharmony_ci .itrim = { 24262306a36Sopenharmony_ci .enable = false, 24362306a36Sopenharmony_ci .timeout = 50000, 24462306a36Sopenharmony_ci }, 24562306a36Sopenharmony_ci .pm_config = { 24662306a36Sopenharmony_ci .host_clk_settling_time = 5000, 24762306a36Sopenharmony_ci .host_fast_wakeup_support = CONF_FAST_WAKEUP_DISABLE, 24862306a36Sopenharmony_ci }, 24962306a36Sopenharmony_ci .roam_trigger = { 25062306a36Sopenharmony_ci .trigger_pacing = 1, 25162306a36Sopenharmony_ci .avg_weight_rssi_beacon = 20, 25262306a36Sopenharmony_ci .avg_weight_rssi_data = 10, 25362306a36Sopenharmony_ci .avg_weight_snr_beacon = 20, 25462306a36Sopenharmony_ci .avg_weight_snr_data = 10, 25562306a36Sopenharmony_ci }, 25662306a36Sopenharmony_ci .scan = { 25762306a36Sopenharmony_ci .min_dwell_time_active = 7500, 25862306a36Sopenharmony_ci .max_dwell_time_active = 30000, 25962306a36Sopenharmony_ci .min_dwell_time_active_long = 25000, 26062306a36Sopenharmony_ci .max_dwell_time_active_long = 50000, 26162306a36Sopenharmony_ci .dwell_time_passive = 100000, 26262306a36Sopenharmony_ci .dwell_time_dfs = 150000, 26362306a36Sopenharmony_ci .num_probe_reqs = 2, 26462306a36Sopenharmony_ci .split_scan_timeout = 50000, 26562306a36Sopenharmony_ci }, 26662306a36Sopenharmony_ci .sched_scan = { 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * Values are in TU/1000 but since sched scan FW command 26962306a36Sopenharmony_ci * params are in TUs rounding up may occur. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci .base_dwell_time = 7500, 27262306a36Sopenharmony_ci .max_dwell_time_delta = 22500, 27362306a36Sopenharmony_ci /* based on 250bits per probe @1Mbps */ 27462306a36Sopenharmony_ci .dwell_time_delta_per_probe = 2000, 27562306a36Sopenharmony_ci /* based on 250bits per probe @6Mbps (plus a bit more) */ 27662306a36Sopenharmony_ci .dwell_time_delta_per_probe_5 = 350, 27762306a36Sopenharmony_ci .dwell_time_passive = 100000, 27862306a36Sopenharmony_ci .dwell_time_dfs = 150000, 27962306a36Sopenharmony_ci .num_probe_reqs = 2, 28062306a36Sopenharmony_ci .rssi_threshold = -90, 28162306a36Sopenharmony_ci .snr_threshold = 0, 28262306a36Sopenharmony_ci }, 28362306a36Sopenharmony_ci .ht = { 28462306a36Sopenharmony_ci .rx_ba_win_size = 8, 28562306a36Sopenharmony_ci .tx_ba_win_size = 64, 28662306a36Sopenharmony_ci .inactivity_timeout = 10000, 28762306a36Sopenharmony_ci .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, 28862306a36Sopenharmony_ci }, 28962306a36Sopenharmony_ci /* 29062306a36Sopenharmony_ci * Memory config for wl127x chips is given in the 29162306a36Sopenharmony_ci * wl12xx_default_priv_conf struct. The below configuration is 29262306a36Sopenharmony_ci * for wl128x chips. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci .mem = { 29562306a36Sopenharmony_ci .num_stations = 1, 29662306a36Sopenharmony_ci .ssid_profiles = 1, 29762306a36Sopenharmony_ci .rx_block_num = 40, 29862306a36Sopenharmony_ci .tx_min_block_num = 40, 29962306a36Sopenharmony_ci .dynamic_memory = 1, 30062306a36Sopenharmony_ci .min_req_tx_blocks = 45, 30162306a36Sopenharmony_ci .min_req_rx_blocks = 22, 30262306a36Sopenharmony_ci .tx_min = 27, 30362306a36Sopenharmony_ci }, 30462306a36Sopenharmony_ci .fm_coex = { 30562306a36Sopenharmony_ci .enable = true, 30662306a36Sopenharmony_ci .swallow_period = 5, 30762306a36Sopenharmony_ci .n_divider_fref_set_1 = 0xff, /* default */ 30862306a36Sopenharmony_ci .n_divider_fref_set_2 = 12, 30962306a36Sopenharmony_ci .m_divider_fref_set_1 = 0xffff, 31062306a36Sopenharmony_ci .m_divider_fref_set_2 = 148, /* default */ 31162306a36Sopenharmony_ci .coex_pll_stabilization_time = 0xffffffff, /* default */ 31262306a36Sopenharmony_ci .ldo_stabilization_time = 0xffff, /* default */ 31362306a36Sopenharmony_ci .fm_disturbed_band_margin = 0xff, /* default */ 31462306a36Sopenharmony_ci .swallow_clk_diff = 0xff, /* default */ 31562306a36Sopenharmony_ci }, 31662306a36Sopenharmony_ci .rx_streaming = { 31762306a36Sopenharmony_ci .duration = 150, 31862306a36Sopenharmony_ci .queues = 0x1, 31962306a36Sopenharmony_ci .interval = 20, 32062306a36Sopenharmony_ci .always = 0, 32162306a36Sopenharmony_ci }, 32262306a36Sopenharmony_ci .fwlog = { 32362306a36Sopenharmony_ci .mode = WL12XX_FWLOG_CONTINUOUS, 32462306a36Sopenharmony_ci .mem_blocks = 2, 32562306a36Sopenharmony_ci .severity = 0, 32662306a36Sopenharmony_ci .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED, 32762306a36Sopenharmony_ci .output = WL12XX_FWLOG_OUTPUT_DBG_PINS, 32862306a36Sopenharmony_ci .threshold = 0, 32962306a36Sopenharmony_ci }, 33062306a36Sopenharmony_ci .rate = { 33162306a36Sopenharmony_ci .rate_retry_score = 32000, 33262306a36Sopenharmony_ci .per_add = 8192, 33362306a36Sopenharmony_ci .per_th1 = 2048, 33462306a36Sopenharmony_ci .per_th2 = 4096, 33562306a36Sopenharmony_ci .max_per = 8100, 33662306a36Sopenharmony_ci .inverse_curiosity_factor = 5, 33762306a36Sopenharmony_ci .tx_fail_low_th = 4, 33862306a36Sopenharmony_ci .tx_fail_high_th = 10, 33962306a36Sopenharmony_ci .per_alpha_shift = 4, 34062306a36Sopenharmony_ci .per_add_shift = 13, 34162306a36Sopenharmony_ci .per_beta1_shift = 10, 34262306a36Sopenharmony_ci .per_beta2_shift = 8, 34362306a36Sopenharmony_ci .rate_check_up = 2, 34462306a36Sopenharmony_ci .rate_check_down = 12, 34562306a36Sopenharmony_ci .rate_retry_policy = { 34662306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 34762306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 34862306a36Sopenharmony_ci 0x00, 0x00, 0x00, 34962306a36Sopenharmony_ci }, 35062306a36Sopenharmony_ci }, 35162306a36Sopenharmony_ci .hangover = { 35262306a36Sopenharmony_ci .recover_time = 0, 35362306a36Sopenharmony_ci .hangover_period = 20, 35462306a36Sopenharmony_ci .dynamic_mode = 1, 35562306a36Sopenharmony_ci .early_termination_mode = 1, 35662306a36Sopenharmony_ci .max_period = 20, 35762306a36Sopenharmony_ci .min_period = 1, 35862306a36Sopenharmony_ci .increase_delta = 1, 35962306a36Sopenharmony_ci .decrease_delta = 2, 36062306a36Sopenharmony_ci .quiet_time = 4, 36162306a36Sopenharmony_ci .increase_time = 1, 36262306a36Sopenharmony_ci .window_size = 16, 36362306a36Sopenharmony_ci }, 36462306a36Sopenharmony_ci .recovery = { 36562306a36Sopenharmony_ci .bug_on_recovery = 0, 36662306a36Sopenharmony_ci .no_recovery = 0, 36762306a36Sopenharmony_ci }, 36862306a36Sopenharmony_ci}; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic struct wl12xx_priv_conf wl12xx_default_priv_conf = { 37162306a36Sopenharmony_ci .rf = { 37262306a36Sopenharmony_ci .tx_per_channel_power_compensation_2 = { 37362306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37462306a36Sopenharmony_ci }, 37562306a36Sopenharmony_ci .tx_per_channel_power_compensation_5 = { 37662306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37762306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37862306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37962306a36Sopenharmony_ci }, 38062306a36Sopenharmony_ci }, 38162306a36Sopenharmony_ci .mem_wl127x = { 38262306a36Sopenharmony_ci .num_stations = 1, 38362306a36Sopenharmony_ci .ssid_profiles = 1, 38462306a36Sopenharmony_ci .rx_block_num = 70, 38562306a36Sopenharmony_ci .tx_min_block_num = 40, 38662306a36Sopenharmony_ci .dynamic_memory = 1, 38762306a36Sopenharmony_ci .min_req_tx_blocks = 100, 38862306a36Sopenharmony_ci .min_req_rx_blocks = 22, 38962306a36Sopenharmony_ci .tx_min = 27, 39062306a36Sopenharmony_ci }, 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci}; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci#define WL12XX_TX_HW_BLOCK_SPARE_DEFAULT 1 39562306a36Sopenharmony_ci#define WL12XX_TX_HW_BLOCK_GEM_SPARE 2 39662306a36Sopenharmony_ci#define WL12XX_TX_HW_BLOCK_SIZE 252 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic const u8 wl12xx_rate_to_idx_2ghz[] = { 39962306a36Sopenharmony_ci /* MCS rates are used only with 11n */ 40062306a36Sopenharmony_ci 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */ 40162306a36Sopenharmony_ci 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */ 40262306a36Sopenharmony_ci 6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */ 40362306a36Sopenharmony_ci 5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */ 40462306a36Sopenharmony_ci 4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */ 40562306a36Sopenharmony_ci 3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */ 40662306a36Sopenharmony_ci 2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */ 40762306a36Sopenharmony_ci 1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */ 40862306a36Sopenharmony_ci 0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */ 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci 11, /* WL12XX_CONF_HW_RXTX_RATE_54 */ 41162306a36Sopenharmony_ci 10, /* WL12XX_CONF_HW_RXTX_RATE_48 */ 41262306a36Sopenharmony_ci 9, /* WL12XX_CONF_HW_RXTX_RATE_36 */ 41362306a36Sopenharmony_ci 8, /* WL12XX_CONF_HW_RXTX_RATE_24 */ 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* TI-specific rate */ 41662306a36Sopenharmony_ci CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */ 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci 7, /* WL12XX_CONF_HW_RXTX_RATE_18 */ 41962306a36Sopenharmony_ci 6, /* WL12XX_CONF_HW_RXTX_RATE_12 */ 42062306a36Sopenharmony_ci 3, /* WL12XX_CONF_HW_RXTX_RATE_11 */ 42162306a36Sopenharmony_ci 5, /* WL12XX_CONF_HW_RXTX_RATE_9 */ 42262306a36Sopenharmony_ci 4, /* WL12XX_CONF_HW_RXTX_RATE_6 */ 42362306a36Sopenharmony_ci 2, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */ 42462306a36Sopenharmony_ci 1, /* WL12XX_CONF_HW_RXTX_RATE_2 */ 42562306a36Sopenharmony_ci 0 /* WL12XX_CONF_HW_RXTX_RATE_1 */ 42662306a36Sopenharmony_ci}; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic const u8 wl12xx_rate_to_idx_5ghz[] = { 42962306a36Sopenharmony_ci /* MCS rates are used only with 11n */ 43062306a36Sopenharmony_ci 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI */ 43162306a36Sopenharmony_ci 7, /* WL12XX_CONF_HW_RXTX_RATE_MCS7 */ 43262306a36Sopenharmony_ci 6, /* WL12XX_CONF_HW_RXTX_RATE_MCS6 */ 43362306a36Sopenharmony_ci 5, /* WL12XX_CONF_HW_RXTX_RATE_MCS5 */ 43462306a36Sopenharmony_ci 4, /* WL12XX_CONF_HW_RXTX_RATE_MCS4 */ 43562306a36Sopenharmony_ci 3, /* WL12XX_CONF_HW_RXTX_RATE_MCS3 */ 43662306a36Sopenharmony_ci 2, /* WL12XX_CONF_HW_RXTX_RATE_MCS2 */ 43762306a36Sopenharmony_ci 1, /* WL12XX_CONF_HW_RXTX_RATE_MCS1 */ 43862306a36Sopenharmony_ci 0, /* WL12XX_CONF_HW_RXTX_RATE_MCS0 */ 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci 7, /* WL12XX_CONF_HW_RXTX_RATE_54 */ 44162306a36Sopenharmony_ci 6, /* WL12XX_CONF_HW_RXTX_RATE_48 */ 44262306a36Sopenharmony_ci 5, /* WL12XX_CONF_HW_RXTX_RATE_36 */ 44362306a36Sopenharmony_ci 4, /* WL12XX_CONF_HW_RXTX_RATE_24 */ 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* TI-specific rate */ 44662306a36Sopenharmony_ci CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_22 */ 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci 3, /* WL12XX_CONF_HW_RXTX_RATE_18 */ 44962306a36Sopenharmony_ci 2, /* WL12XX_CONF_HW_RXTX_RATE_12 */ 45062306a36Sopenharmony_ci CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_11 */ 45162306a36Sopenharmony_ci 1, /* WL12XX_CONF_HW_RXTX_RATE_9 */ 45262306a36Sopenharmony_ci 0, /* WL12XX_CONF_HW_RXTX_RATE_6 */ 45362306a36Sopenharmony_ci CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_5_5 */ 45462306a36Sopenharmony_ci CONF_HW_RXTX_RATE_UNSUPPORTED, /* WL12XX_CONF_HW_RXTX_RATE_2 */ 45562306a36Sopenharmony_ci CONF_HW_RXTX_RATE_UNSUPPORTED /* WL12XX_CONF_HW_RXTX_RATE_1 */ 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic const u8 *wl12xx_band_rate_to_idx[] = { 45962306a36Sopenharmony_ci [NL80211_BAND_2GHZ] = wl12xx_rate_to_idx_2ghz, 46062306a36Sopenharmony_ci [NL80211_BAND_5GHZ] = wl12xx_rate_to_idx_5ghz 46162306a36Sopenharmony_ci}; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cienum wl12xx_hw_rates { 46462306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS7_SGI = 0, 46562306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS7, 46662306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS6, 46762306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS5, 46862306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS4, 46962306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS3, 47062306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS2, 47162306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS1, 47262306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MCS0, 47362306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_54, 47462306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_48, 47562306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_36, 47662306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_24, 47762306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_22, 47862306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_18, 47962306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_12, 48062306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_11, 48162306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_9, 48262306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_6, 48362306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_5_5, 48462306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_2, 48562306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_1, 48662306a36Sopenharmony_ci WL12XX_CONF_HW_RXTX_RATE_MAX, 48762306a36Sopenharmony_ci}; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic struct wlcore_partition_set wl12xx_ptable[PART_TABLE_LEN] = { 49062306a36Sopenharmony_ci [PART_DOWN] = { 49162306a36Sopenharmony_ci .mem = { 49262306a36Sopenharmony_ci .start = 0x00000000, 49362306a36Sopenharmony_ci .size = 0x000177c0 49462306a36Sopenharmony_ci }, 49562306a36Sopenharmony_ci .reg = { 49662306a36Sopenharmony_ci .start = REGISTERS_BASE, 49762306a36Sopenharmony_ci .size = 0x00008800 49862306a36Sopenharmony_ci }, 49962306a36Sopenharmony_ci .mem2 = { 50062306a36Sopenharmony_ci .start = 0x00000000, 50162306a36Sopenharmony_ci .size = 0x00000000 50262306a36Sopenharmony_ci }, 50362306a36Sopenharmony_ci .mem3 = { 50462306a36Sopenharmony_ci .start = 0x00000000, 50562306a36Sopenharmony_ci .size = 0x00000000 50662306a36Sopenharmony_ci }, 50762306a36Sopenharmony_ci }, 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci [PART_BOOT] = { /* in wl12xx we can use a mix of work and down 51062306a36Sopenharmony_ci * partition here */ 51162306a36Sopenharmony_ci .mem = { 51262306a36Sopenharmony_ci .start = 0x00040000, 51362306a36Sopenharmony_ci .size = 0x00014fc0 51462306a36Sopenharmony_ci }, 51562306a36Sopenharmony_ci .reg = { 51662306a36Sopenharmony_ci .start = REGISTERS_BASE, 51762306a36Sopenharmony_ci .size = 0x00008800 51862306a36Sopenharmony_ci }, 51962306a36Sopenharmony_ci .mem2 = { 52062306a36Sopenharmony_ci .start = 0x00000000, 52162306a36Sopenharmony_ci .size = 0x00000000 52262306a36Sopenharmony_ci }, 52362306a36Sopenharmony_ci .mem3 = { 52462306a36Sopenharmony_ci .start = 0x00000000, 52562306a36Sopenharmony_ci .size = 0x00000000 52662306a36Sopenharmony_ci }, 52762306a36Sopenharmony_ci }, 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci [PART_WORK] = { 53062306a36Sopenharmony_ci .mem = { 53162306a36Sopenharmony_ci .start = 0x00040000, 53262306a36Sopenharmony_ci .size = 0x00014fc0 53362306a36Sopenharmony_ci }, 53462306a36Sopenharmony_ci .reg = { 53562306a36Sopenharmony_ci .start = REGISTERS_BASE, 53662306a36Sopenharmony_ci .size = 0x0000a000 53762306a36Sopenharmony_ci }, 53862306a36Sopenharmony_ci .mem2 = { 53962306a36Sopenharmony_ci .start = 0x003004f8, 54062306a36Sopenharmony_ci .size = 0x00000004 54162306a36Sopenharmony_ci }, 54262306a36Sopenharmony_ci .mem3 = { 54362306a36Sopenharmony_ci .start = 0x00000000, 54462306a36Sopenharmony_ci .size = 0x00040404 54562306a36Sopenharmony_ci }, 54662306a36Sopenharmony_ci }, 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci [PART_DRPW] = { 54962306a36Sopenharmony_ci .mem = { 55062306a36Sopenharmony_ci .start = 0x00040000, 55162306a36Sopenharmony_ci .size = 0x00014fc0 55262306a36Sopenharmony_ci }, 55362306a36Sopenharmony_ci .reg = { 55462306a36Sopenharmony_ci .start = DRPW_BASE, 55562306a36Sopenharmony_ci .size = 0x00006000 55662306a36Sopenharmony_ci }, 55762306a36Sopenharmony_ci .mem2 = { 55862306a36Sopenharmony_ci .start = 0x00000000, 55962306a36Sopenharmony_ci .size = 0x00000000 56062306a36Sopenharmony_ci }, 56162306a36Sopenharmony_ci .mem3 = { 56262306a36Sopenharmony_ci .start = 0x00000000, 56362306a36Sopenharmony_ci .size = 0x00000000 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci}; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic const int wl12xx_rtable[REG_TABLE_LEN] = { 56962306a36Sopenharmony_ci [REG_ECPU_CONTROL] = WL12XX_REG_ECPU_CONTROL, 57062306a36Sopenharmony_ci [REG_INTERRUPT_NO_CLEAR] = WL12XX_REG_INTERRUPT_NO_CLEAR, 57162306a36Sopenharmony_ci [REG_INTERRUPT_ACK] = WL12XX_REG_INTERRUPT_ACK, 57262306a36Sopenharmony_ci [REG_COMMAND_MAILBOX_PTR] = WL12XX_REG_COMMAND_MAILBOX_PTR, 57362306a36Sopenharmony_ci [REG_EVENT_MAILBOX_PTR] = WL12XX_REG_EVENT_MAILBOX_PTR, 57462306a36Sopenharmony_ci [REG_INTERRUPT_TRIG] = WL12XX_REG_INTERRUPT_TRIG, 57562306a36Sopenharmony_ci [REG_INTERRUPT_MASK] = WL12XX_REG_INTERRUPT_MASK, 57662306a36Sopenharmony_ci [REG_PC_ON_RECOVERY] = WL12XX_SCR_PAD4, 57762306a36Sopenharmony_ci [REG_CHIP_ID_B] = WL12XX_CHIP_ID_B, 57862306a36Sopenharmony_ci [REG_CMD_MBOX_ADDRESS] = WL12XX_CMD_MBOX_ADDRESS, 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* data access memory addresses, used with partition translation */ 58162306a36Sopenharmony_ci [REG_SLV_MEM_DATA] = WL1271_SLV_MEM_DATA, 58262306a36Sopenharmony_ci [REG_SLV_REG_DATA] = WL1271_SLV_REG_DATA, 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* raw data access memory addresses */ 58562306a36Sopenharmony_ci [REG_RAW_FW_STATUS_ADDR] = FW_STATUS_ADDR, 58662306a36Sopenharmony_ci}; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* TODO: maybe move to a new header file? */ 58962306a36Sopenharmony_ci#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-5-mr.bin" 59062306a36Sopenharmony_ci#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-5-sr.bin" 59162306a36Sopenharmony_ci#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-5-plt.bin" 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-5-mr.bin" 59462306a36Sopenharmony_ci#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-5-sr.bin" 59562306a36Sopenharmony_ci#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-5-plt.bin" 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci int ret; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (wl->chip.id != CHIP_ID_128X_PG20) { 60262306a36Sopenharmony_ci struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; 60362306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* 60662306a36Sopenharmony_ci * Choose the block we want to read 60762306a36Sopenharmony_ci * For aggregated packets, only the first memory block 60862306a36Sopenharmony_ci * should be retrieved. The FW takes care of the rest. 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_ci u32 mem_block = rx_desc & RX_MEM_BLOCK_MASK; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci priv->rx_mem_addr->addr = (mem_block << 8) + 61362306a36Sopenharmony_ci le32_to_cpu(wl_mem_map->packet_memory_pool_start); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci priv->rx_mem_addr->addr_extra = priv->rx_mem_addr->addr + 4; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci ret = wlcore_write(wl, WL1271_SLV_REG_DATA, priv->rx_mem_addr, 61862306a36Sopenharmony_ci sizeof(*priv->rx_mem_addr), false); 61962306a36Sopenharmony_ci if (ret < 0) 62062306a36Sopenharmony_ci return ret; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int wl12xx_identify_chip(struct wl1271 *wl) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci int ret = 0; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci switch (wl->chip.id) { 63162306a36Sopenharmony_ci case CHIP_ID_127X_PG10: 63262306a36Sopenharmony_ci wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete", 63362306a36Sopenharmony_ci wl->chip.id); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | 63662306a36Sopenharmony_ci WLCORE_QUIRK_DUAL_PROBE_TMPL | 63762306a36Sopenharmony_ci WLCORE_QUIRK_TKIP_HEADER_SPACE | 63862306a36Sopenharmony_ci WLCORE_QUIRK_AP_ZERO_SESSION_ID; 63962306a36Sopenharmony_ci wl->sr_fw_name = WL127X_FW_NAME_SINGLE; 64062306a36Sopenharmony_ci wl->mr_fw_name = WL127X_FW_NAME_MULTI; 64162306a36Sopenharmony_ci memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, 64262306a36Sopenharmony_ci sizeof(wl->conf.mem)); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* read data preparation is only needed by wl127x */ 64562306a36Sopenharmony_ci wl->ops->prepare_read = wl127x_prepare_read; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, 64862306a36Sopenharmony_ci WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER, 64962306a36Sopenharmony_ci WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER, 65062306a36Sopenharmony_ci WL127X_IFTYPE_MR_VER, WL127X_MAJOR_MR_VER, 65162306a36Sopenharmony_ci WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER); 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci case CHIP_ID_127X_PG20: 65562306a36Sopenharmony_ci wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", 65662306a36Sopenharmony_ci wl->chip.id); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | 65962306a36Sopenharmony_ci WLCORE_QUIRK_DUAL_PROBE_TMPL | 66062306a36Sopenharmony_ci WLCORE_QUIRK_TKIP_HEADER_SPACE | 66162306a36Sopenharmony_ci WLCORE_QUIRK_AP_ZERO_SESSION_ID; 66262306a36Sopenharmony_ci wl->plt_fw_name = WL127X_PLT_FW_NAME; 66362306a36Sopenharmony_ci wl->sr_fw_name = WL127X_FW_NAME_SINGLE; 66462306a36Sopenharmony_ci wl->mr_fw_name = WL127X_FW_NAME_MULTI; 66562306a36Sopenharmony_ci memcpy(&wl->conf.mem, &wl12xx_default_priv_conf.mem_wl127x, 66662306a36Sopenharmony_ci sizeof(wl->conf.mem)); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* read data preparation is only needed by wl127x */ 66962306a36Sopenharmony_ci wl->ops->prepare_read = wl127x_prepare_read; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, 67262306a36Sopenharmony_ci WL127X_IFTYPE_SR_VER, WL127X_MAJOR_SR_VER, 67362306a36Sopenharmony_ci WL127X_SUBTYPE_SR_VER, WL127X_MINOR_SR_VER, 67462306a36Sopenharmony_ci WL127X_IFTYPE_MR_VER, WL127X_MAJOR_MR_VER, 67562306a36Sopenharmony_ci WL127X_SUBTYPE_MR_VER, WL127X_MINOR_MR_VER); 67662306a36Sopenharmony_ci break; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci case CHIP_ID_128X_PG20: 67962306a36Sopenharmony_ci wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", 68062306a36Sopenharmony_ci wl->chip.id); 68162306a36Sopenharmony_ci wl->plt_fw_name = WL128X_PLT_FW_NAME; 68262306a36Sopenharmony_ci wl->sr_fw_name = WL128X_FW_NAME_SINGLE; 68362306a36Sopenharmony_ci wl->mr_fw_name = WL128X_FW_NAME_MULTI; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* wl128x requires TX blocksize alignment */ 68662306a36Sopenharmony_ci wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | 68762306a36Sopenharmony_ci WLCORE_QUIRK_DUAL_PROBE_TMPL | 68862306a36Sopenharmony_ci WLCORE_QUIRK_TKIP_HEADER_SPACE | 68962306a36Sopenharmony_ci WLCORE_QUIRK_AP_ZERO_SESSION_ID; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, 69262306a36Sopenharmony_ci WL128X_IFTYPE_SR_VER, WL128X_MAJOR_SR_VER, 69362306a36Sopenharmony_ci WL128X_SUBTYPE_SR_VER, WL128X_MINOR_SR_VER, 69462306a36Sopenharmony_ci WL128X_IFTYPE_MR_VER, WL128X_MAJOR_MR_VER, 69562306a36Sopenharmony_ci WL128X_SUBTYPE_MR_VER, WL128X_MINOR_MR_VER); 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci case CHIP_ID_128X_PG10: 69862306a36Sopenharmony_ci default: 69962306a36Sopenharmony_ci wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); 70062306a36Sopenharmony_ci ret = -ENODEV; 70162306a36Sopenharmony_ci goto out; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci wl->fw_mem_block_size = 256; 70562306a36Sopenharmony_ci wl->fwlog_end = 0x2000000; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* common settings */ 70862306a36Sopenharmony_ci wl->scan_templ_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4_LEGACY; 70962306a36Sopenharmony_ci wl->scan_templ_id_5 = CMD_TEMPL_APP_PROBE_REQ_5_LEGACY; 71062306a36Sopenharmony_ci wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; 71162306a36Sopenharmony_ci wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; 71262306a36Sopenharmony_ci wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ; 71362306a36Sopenharmony_ci wl->ba_rx_session_count_max = WL12XX_RX_BA_MAX_SESSIONS; 71462306a36Sopenharmony_ciout: 71562306a36Sopenharmony_ci return ret; 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic int __must_check wl12xx_top_reg_write(struct wl1271 *wl, int addr, 71962306a36Sopenharmony_ci u16 val) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci int ret; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* write address >> 1 + 0x30000 to OCP_POR_CTR */ 72462306a36Sopenharmony_ci addr = (addr >> 1) + 0x30000; 72562306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr); 72662306a36Sopenharmony_ci if (ret < 0) 72762306a36Sopenharmony_ci goto out; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* write value to OCP_POR_WDATA */ 73062306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_OCP_DATA_WRITE, val); 73162306a36Sopenharmony_ci if (ret < 0) 73262306a36Sopenharmony_ci goto out; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* write 1 to OCP_CMD */ 73562306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE); 73662306a36Sopenharmony_ci if (ret < 0) 73762306a36Sopenharmony_ci goto out; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ciout: 74062306a36Sopenharmony_ci return ret; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic int __must_check wl12xx_top_reg_read(struct wl1271 *wl, int addr, 74462306a36Sopenharmony_ci u16 *out) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci u32 val; 74762306a36Sopenharmony_ci int timeout = OCP_CMD_LOOP; 74862306a36Sopenharmony_ci int ret; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* write address >> 1 + 0x30000 to OCP_POR_CTR */ 75162306a36Sopenharmony_ci addr = (addr >> 1) + 0x30000; 75262306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr); 75362306a36Sopenharmony_ci if (ret < 0) 75462306a36Sopenharmony_ci return ret; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* write 2 to OCP_CMD */ 75762306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ); 75862306a36Sopenharmony_ci if (ret < 0) 75962306a36Sopenharmony_ci return ret; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* poll for data ready */ 76262306a36Sopenharmony_ci do { 76362306a36Sopenharmony_ci ret = wlcore_read32(wl, WL12XX_OCP_DATA_READ, &val); 76462306a36Sopenharmony_ci if (ret < 0) 76562306a36Sopenharmony_ci return ret; 76662306a36Sopenharmony_ci } while (!(val & OCP_READY_MASK) && --timeout); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (!timeout) { 76962306a36Sopenharmony_ci wl1271_warning("Top register access timed out."); 77062306a36Sopenharmony_ci return -ETIMEDOUT; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* check data status and return if OK */ 77462306a36Sopenharmony_ci if ((val & OCP_STATUS_MASK) != OCP_STATUS_OK) { 77562306a36Sopenharmony_ci wl1271_warning("Top register access returned error."); 77662306a36Sopenharmony_ci return -EIO; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (out) 78062306a36Sopenharmony_ci *out = val & 0xffff; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci u16 spare_reg; 78862306a36Sopenharmony_ci int ret; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ 79162306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg); 79262306a36Sopenharmony_ci if (ret < 0) 79362306a36Sopenharmony_ci return ret; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (spare_reg == 0xFFFF) 79662306a36Sopenharmony_ci return -EFAULT; 79762306a36Sopenharmony_ci spare_reg |= (BIT(3) | BIT(5) | BIT(6)); 79862306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); 79962306a36Sopenharmony_ci if (ret < 0) 80062306a36Sopenharmony_ci return ret; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ 80362306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG, 80462306a36Sopenharmony_ci WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); 80562306a36Sopenharmony_ci if (ret < 0) 80662306a36Sopenharmony_ci return ret; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* Delay execution for 15msec, to let the HW settle */ 80962306a36Sopenharmony_ci mdelay(15); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic bool wl128x_is_tcxo_valid(struct wl1271 *wl) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci u16 tcxo_detection; 81762306a36Sopenharmony_ci int ret; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG, &tcxo_detection); 82062306a36Sopenharmony_ci if (ret < 0) 82162306a36Sopenharmony_ci return false; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (tcxo_detection & TCXO_DET_FAILED) 82462306a36Sopenharmony_ci return false; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return true; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic bool wl128x_is_fref_valid(struct wl1271 *wl) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci u16 fref_detection; 83262306a36Sopenharmony_ci int ret; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG, &fref_detection); 83562306a36Sopenharmony_ci if (ret < 0) 83662306a36Sopenharmony_ci return false; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (fref_detection & FREF_CLK_DETECT_FAIL) 83962306a36Sopenharmony_ci return false; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci return true; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci int ret; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); 84962306a36Sopenharmony_ci if (ret < 0) 85062306a36Sopenharmony_ci goto out; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); 85362306a36Sopenharmony_ci if (ret < 0) 85462306a36Sopenharmony_ci goto out; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, 85762306a36Sopenharmony_ci MCS_PLL_CONFIG_REG_VAL); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ciout: 86062306a36Sopenharmony_ci return ret; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci u16 spare_reg; 86662306a36Sopenharmony_ci u16 pll_config; 86762306a36Sopenharmony_ci u8 input_freq; 86862306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 86962306a36Sopenharmony_ci int ret; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* Mask bits [3:1] in the sys_clk_cfg register */ 87262306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg); 87362306a36Sopenharmony_ci if (ret < 0) 87462306a36Sopenharmony_ci return ret; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (spare_reg == 0xFFFF) 87762306a36Sopenharmony_ci return -EFAULT; 87862306a36Sopenharmony_ci spare_reg |= BIT(2); 87962306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); 88062306a36Sopenharmony_ci if (ret < 0) 88162306a36Sopenharmony_ci return ret; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* Handle special cases of the TCXO clock */ 88462306a36Sopenharmony_ci if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || 88562306a36Sopenharmony_ci priv->tcxo_clock == WL12XX_TCXOCLOCK_33_6) 88662306a36Sopenharmony_ci return wl128x_manually_configure_mcs_pll(wl); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* Set the input frequency according to the selected clock source */ 88962306a36Sopenharmony_ci input_freq = (clk & 1) + 1; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG, &pll_config); 89262306a36Sopenharmony_ci if (ret < 0) 89362306a36Sopenharmony_ci return ret; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (pll_config == 0xFFFF) 89662306a36Sopenharmony_ci return -EFAULT; 89762306a36Sopenharmony_ci pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); 89862306a36Sopenharmony_ci pll_config |= MCS_PLL_ENABLE_HP; 89962306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci return ret; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci/* 90562306a36Sopenharmony_ci * WL128x has two clocks input - TCXO and FREF. 90662306a36Sopenharmony_ci * TCXO is the main clock of the device, while FREF is used to sync 90762306a36Sopenharmony_ci * between the GPS and the cellular modem. 90862306a36Sopenharmony_ci * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used 90962306a36Sopenharmony_ci * as the WLAN/BT main clock. 91062306a36Sopenharmony_ci */ 91162306a36Sopenharmony_cistatic int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 91462306a36Sopenharmony_ci u16 sys_clk_cfg; 91562306a36Sopenharmony_ci int ret; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* For XTAL-only modes, FREF will be used after switching from TCXO */ 91862306a36Sopenharmony_ci if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL || 91962306a36Sopenharmony_ci priv->ref_clock == WL12XX_REFCLOCK_38_XTAL) { 92062306a36Sopenharmony_ci if (!wl128x_switch_tcxo_to_fref(wl)) 92162306a36Sopenharmony_ci return -EINVAL; 92262306a36Sopenharmony_ci goto fref_clk; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* Query the HW, to determine which clock source we should use */ 92662306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG, &sys_clk_cfg); 92762306a36Sopenharmony_ci if (ret < 0) 92862306a36Sopenharmony_ci return ret; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (sys_clk_cfg == 0xFFFF) 93162306a36Sopenharmony_ci return -EINVAL; 93262306a36Sopenharmony_ci if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) 93362306a36Sopenharmony_ci goto fref_clk; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ 93662306a36Sopenharmony_ci if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || 93762306a36Sopenharmony_ci priv->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { 93862306a36Sopenharmony_ci if (!wl128x_switch_tcxo_to_fref(wl)) 93962306a36Sopenharmony_ci return -EINVAL; 94062306a36Sopenharmony_ci goto fref_clk; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* TCXO clock is selected */ 94462306a36Sopenharmony_ci if (!wl128x_is_tcxo_valid(wl)) 94562306a36Sopenharmony_ci return -EINVAL; 94662306a36Sopenharmony_ci *selected_clock = priv->tcxo_clock; 94762306a36Sopenharmony_ci goto config_mcs_pll; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cifref_clk: 95062306a36Sopenharmony_ci /* FREF clock is selected */ 95162306a36Sopenharmony_ci if (!wl128x_is_fref_valid(wl)) 95262306a36Sopenharmony_ci return -EINVAL; 95362306a36Sopenharmony_ci *selected_clock = priv->ref_clock; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ciconfig_mcs_pll: 95662306a36Sopenharmony_ci return wl128x_configure_mcs_pll(wl, *selected_clock); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic int wl127x_boot_clk(struct wl1271 *wl) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 96262306a36Sopenharmony_ci u32 pause; 96362306a36Sopenharmony_ci u32 clk; 96462306a36Sopenharmony_ci int ret; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) 96762306a36Sopenharmony_ci wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (priv->ref_clock == CONF_REF_CLK_19_2_E || 97062306a36Sopenharmony_ci priv->ref_clock == CONF_REF_CLK_38_4_E || 97162306a36Sopenharmony_ci priv->ref_clock == CONF_REF_CLK_38_4_M_XTAL) 97262306a36Sopenharmony_ci /* ref clk: 19.2/38.4/38.4-XTAL */ 97362306a36Sopenharmony_ci clk = 0x3; 97462306a36Sopenharmony_ci else if (priv->ref_clock == CONF_REF_CLK_26_E || 97562306a36Sopenharmony_ci priv->ref_clock == CONF_REF_CLK_26_M_XTAL || 97662306a36Sopenharmony_ci priv->ref_clock == CONF_REF_CLK_52_E) 97762306a36Sopenharmony_ci /* ref clk: 26/52 */ 97862306a36Sopenharmony_ci clk = 0x5; 97962306a36Sopenharmony_ci else 98062306a36Sopenharmony_ci return -EINVAL; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (priv->ref_clock != CONF_REF_CLK_19_2_E) { 98362306a36Sopenharmony_ci u16 val; 98462306a36Sopenharmony_ci /* Set clock type (open drain) */ 98562306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE, &val); 98662306a36Sopenharmony_ci if (ret < 0) 98762306a36Sopenharmony_ci goto out; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci val &= FREF_CLK_TYPE_BITS; 99062306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val); 99162306a36Sopenharmony_ci if (ret < 0) 99262306a36Sopenharmony_ci goto out; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* Set clock pull mode (no pull) */ 99562306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL, &val); 99662306a36Sopenharmony_ci if (ret < 0) 99762306a36Sopenharmony_ci goto out; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci val |= NO_PULL; 100062306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val); 100162306a36Sopenharmony_ci if (ret < 0) 100262306a36Sopenharmony_ci goto out; 100362306a36Sopenharmony_ci } else { 100462306a36Sopenharmony_ci u16 val; 100562306a36Sopenharmony_ci /* Set clock polarity */ 100662306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY, &val); 100762306a36Sopenharmony_ci if (ret < 0) 100862306a36Sopenharmony_ci goto out; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci val &= FREF_CLK_POLARITY_BITS; 101162306a36Sopenharmony_ci val |= CLK_REQ_OUTN_SEL; 101262306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); 101362306a36Sopenharmony_ci if (ret < 0) 101462306a36Sopenharmony_ci goto out; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_PLL_PARAMETERS, clk); 101862306a36Sopenharmony_ci if (ret < 0) 101962306a36Sopenharmony_ci goto out; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci ret = wlcore_read32(wl, WL12XX_PLL_PARAMETERS, &pause); 102262306a36Sopenharmony_ci if (ret < 0) 102362306a36Sopenharmony_ci goto out; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci pause &= ~(WU_COUNTER_PAUSE_VAL); 102862306a36Sopenharmony_ci pause |= WU_COUNTER_PAUSE_VAL; 102962306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ciout: 103262306a36Sopenharmony_ci return ret; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic int wl1271_boot_soft_reset(struct wl1271 *wl) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci unsigned long timeout; 103862306a36Sopenharmony_ci u32 boot_data; 103962306a36Sopenharmony_ci int ret = 0; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* perform soft reset */ 104262306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); 104362306a36Sopenharmony_ci if (ret < 0) 104462306a36Sopenharmony_ci goto out; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* SOFT_RESET is self clearing */ 104762306a36Sopenharmony_ci timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); 104862306a36Sopenharmony_ci while (1) { 104962306a36Sopenharmony_ci ret = wlcore_read32(wl, WL12XX_SLV_SOFT_RESET, &boot_data); 105062306a36Sopenharmony_ci if (ret < 0) 105162306a36Sopenharmony_ci goto out; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); 105462306a36Sopenharmony_ci if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (time_after(jiffies, timeout)) { 105862306a36Sopenharmony_ci /* 1.2 check pWhalBus->uSelfClearTime if the 105962306a36Sopenharmony_ci * timeout was reached */ 106062306a36Sopenharmony_ci wl1271_error("soft reset timeout"); 106162306a36Sopenharmony_ci return -1; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci udelay(SOFT_RESET_STALL_TIME); 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* disable Rx/Tx */ 106862306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_ENABLE, 0x0); 106962306a36Sopenharmony_ci if (ret < 0) 107062306a36Sopenharmony_ci goto out; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* disable auto calibration on start*/ 107362306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_SPARE_A2, 0xffff); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ciout: 107662306a36Sopenharmony_ci return ret; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic int wl12xx_pre_boot(struct wl1271 *wl) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 108262306a36Sopenharmony_ci int ret = 0; 108362306a36Sopenharmony_ci u32 clk; 108462306a36Sopenharmony_ci int selected_clock = -1; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (wl->chip.id == CHIP_ID_128X_PG20) { 108762306a36Sopenharmony_ci ret = wl128x_boot_clk(wl, &selected_clock); 108862306a36Sopenharmony_ci if (ret < 0) 108962306a36Sopenharmony_ci goto out; 109062306a36Sopenharmony_ci } else { 109162306a36Sopenharmony_ci ret = wl127x_boot_clk(wl); 109262306a36Sopenharmony_ci if (ret < 0) 109362306a36Sopenharmony_ci goto out; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* Continue the ELP wake up sequence */ 109762306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); 109862306a36Sopenharmony_ci if (ret < 0) 109962306a36Sopenharmony_ci goto out; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci udelay(500); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); 110462306a36Sopenharmony_ci if (ret < 0) 110562306a36Sopenharmony_ci goto out; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* Read-modify-write DRPW_SCRATCH_START register (see next state) 110862306a36Sopenharmony_ci to be used by DRPw FW. The RTRIM value will be added by the FW 110962306a36Sopenharmony_ci before taking DRPw out of reset */ 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci ret = wlcore_read32(wl, WL12XX_DRPW_SCRATCH_START, &clk); 111262306a36Sopenharmony_ci if (ret < 0) 111362306a36Sopenharmony_ci goto out; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (wl->chip.id == CHIP_ID_128X_PG20) 111862306a36Sopenharmony_ci clk |= ((selected_clock & 0x3) << 1) << 4; 111962306a36Sopenharmony_ci else 112062306a36Sopenharmony_ci clk |= (priv->ref_clock << 1) << 4; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_DRPW_SCRATCH_START, clk); 112362306a36Sopenharmony_ci if (ret < 0) 112462306a36Sopenharmony_ci goto out; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]); 112762306a36Sopenharmony_ci if (ret < 0) 112862306a36Sopenharmony_ci goto out; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci /* Disable interrupts */ 113162306a36Sopenharmony_ci ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); 113262306a36Sopenharmony_ci if (ret < 0) 113362306a36Sopenharmony_ci goto out; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci ret = wl1271_boot_soft_reset(wl); 113662306a36Sopenharmony_ci if (ret < 0) 113762306a36Sopenharmony_ci goto out; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ciout: 114062306a36Sopenharmony_ci return ret; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic int wl12xx_pre_upload(struct wl1271 *wl) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci u32 tmp; 114662306a36Sopenharmony_ci u16 polarity; 114762306a36Sopenharmony_ci int ret; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci /* write firmware's last address (ie. it's length) to 115062306a36Sopenharmony_ci * ACX_EEPROMLESS_IND_REG */ 115162306a36Sopenharmony_ci wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND); 115462306a36Sopenharmony_ci if (ret < 0) 115562306a36Sopenharmony_ci goto out; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp); 115862306a36Sopenharmony_ci if (ret < 0) 115962306a36Sopenharmony_ci goto out; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci /* 6. read the EEPROM parameters */ 116462306a36Sopenharmony_ci ret = wlcore_read32(wl, WL12XX_SCR_PAD2, &tmp); 116562306a36Sopenharmony_ci if (ret < 0) 116662306a36Sopenharmony_ci goto out; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci /* WL1271: The reference driver skips steps 7 to 10 (jumps directly 116962306a36Sopenharmony_ci * to upload_fw) */ 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (wl->chip.id == CHIP_ID_128X_PG20) { 117262306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); 117362306a36Sopenharmony_ci if (ret < 0) 117462306a36Sopenharmony_ci goto out; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* polarity must be set before the firmware is loaded */ 117862306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, OCP_REG_POLARITY, &polarity); 117962306a36Sopenharmony_ci if (ret < 0) 118062306a36Sopenharmony_ci goto out; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* We use HIGH polarity, so unset the LOW bit */ 118362306a36Sopenharmony_ci polarity &= ~POLARITY_LOW; 118462306a36Sopenharmony_ci ret = wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ciout: 118762306a36Sopenharmony_ci return ret; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic int wl12xx_enable_interrupts(struct wl1271 *wl) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci int ret; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, 119562306a36Sopenharmony_ci WL12XX_ACX_ALL_EVENTS_VECTOR); 119662306a36Sopenharmony_ci if (ret < 0) 119762306a36Sopenharmony_ci goto out; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci wlcore_enable_interrupts(wl); 120062306a36Sopenharmony_ci ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, 120162306a36Sopenharmony_ci WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK)); 120262306a36Sopenharmony_ci if (ret < 0) 120362306a36Sopenharmony_ci goto disable_interrupts; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); 120662306a36Sopenharmony_ci if (ret < 0) 120762306a36Sopenharmony_ci goto disable_interrupts; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci return ret; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cidisable_interrupts: 121262306a36Sopenharmony_ci wlcore_disable_interrupts(wl); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ciout: 121562306a36Sopenharmony_ci return ret; 121662306a36Sopenharmony_ci} 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_cistatic int wl12xx_boot(struct wl1271 *wl) 121962306a36Sopenharmony_ci{ 122062306a36Sopenharmony_ci int ret; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci ret = wl12xx_pre_boot(wl); 122362306a36Sopenharmony_ci if (ret < 0) 122462306a36Sopenharmony_ci goto out; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci ret = wlcore_boot_upload_nvs(wl); 122762306a36Sopenharmony_ci if (ret < 0) 122862306a36Sopenharmony_ci goto out; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci ret = wl12xx_pre_upload(wl); 123162306a36Sopenharmony_ci if (ret < 0) 123262306a36Sopenharmony_ci goto out; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci ret = wlcore_boot_upload_firmware(wl); 123562306a36Sopenharmony_ci if (ret < 0) 123662306a36Sopenharmony_ci goto out; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci wl->event_mask = BSS_LOSE_EVENT_ID | 123962306a36Sopenharmony_ci REGAINED_BSS_EVENT_ID | 124062306a36Sopenharmony_ci SCAN_COMPLETE_EVENT_ID | 124162306a36Sopenharmony_ci ROLE_STOP_COMPLETE_EVENT_ID | 124262306a36Sopenharmony_ci RSSI_SNR_TRIGGER_0_EVENT_ID | 124362306a36Sopenharmony_ci PSPOLL_DELIVERY_FAILURE_EVENT_ID | 124462306a36Sopenharmony_ci SOFT_GEMINI_SENSE_EVENT_ID | 124562306a36Sopenharmony_ci PERIODIC_SCAN_REPORT_EVENT_ID | 124662306a36Sopenharmony_ci PERIODIC_SCAN_COMPLETE_EVENT_ID | 124762306a36Sopenharmony_ci DUMMY_PACKET_EVENT_ID | 124862306a36Sopenharmony_ci PEER_REMOVE_COMPLETE_EVENT_ID | 124962306a36Sopenharmony_ci BA_SESSION_RX_CONSTRAINT_EVENT_ID | 125062306a36Sopenharmony_ci REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | 125162306a36Sopenharmony_ci INACTIVE_STA_EVENT_ID | 125262306a36Sopenharmony_ci CHANNEL_SWITCH_COMPLETE_EVENT_ID; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci wl->ap_event_mask = MAX_TX_RETRY_EVENT_ID; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci ret = wlcore_boot_run_firmware(wl); 125762306a36Sopenharmony_ci if (ret < 0) 125862306a36Sopenharmony_ci goto out; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci ret = wl12xx_enable_interrupts(wl); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ciout: 126362306a36Sopenharmony_ci return ret; 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_cistatic int wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, 126762306a36Sopenharmony_ci void *buf, size_t len) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci int ret; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci ret = wlcore_write(wl, cmd_box_addr, buf, len, false); 127262306a36Sopenharmony_ci if (ret < 0) 127362306a36Sopenharmony_ci return ret; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci ret = wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci return ret; 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic int wl12xx_ack_event(struct wl1271 *wl) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci return wlcore_write_reg(wl, REG_INTERRUPT_TRIG, 128362306a36Sopenharmony_ci WL12XX_INTR_TRIG_EVENT_ACK); 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_cistatic u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci u32 blk_size = WL12XX_TX_HW_BLOCK_SIZE; 128962306a36Sopenharmony_ci u32 align_len = wlcore_calc_packet_alignment(wl, len); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci return (align_len + blk_size - 1) / blk_size + spare_blks; 129262306a36Sopenharmony_ci} 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic void 129562306a36Sopenharmony_ciwl12xx_set_tx_desc_blocks(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, 129662306a36Sopenharmony_ci u32 blks, u32 spare_blks) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci if (wl->chip.id == CHIP_ID_128X_PG20) { 129962306a36Sopenharmony_ci desc->wl128x_mem.total_mem_blocks = blks; 130062306a36Sopenharmony_ci } else { 130162306a36Sopenharmony_ci desc->wl127x_mem.extra_blocks = spare_blks; 130262306a36Sopenharmony_ci desc->wl127x_mem.total_mem_blocks = blks; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic void 130762306a36Sopenharmony_ciwl12xx_set_tx_desc_data_len(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, 130862306a36Sopenharmony_ci struct sk_buff *skb) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci u32 aligned_len = wlcore_calc_packet_alignment(wl, skb->len); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci if (wl->chip.id == CHIP_ID_128X_PG20) { 131362306a36Sopenharmony_ci desc->wl128x_mem.extra_bytes = aligned_len - skb->len; 131462306a36Sopenharmony_ci desc->length = cpu_to_le16(aligned_len >> 2); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci wl1271_debug(DEBUG_TX, 131762306a36Sopenharmony_ci "tx_fill_hdr: hlid: %d len: %d life: %d mem: %d extra: %d", 131862306a36Sopenharmony_ci desc->hlid, 131962306a36Sopenharmony_ci le16_to_cpu(desc->length), 132062306a36Sopenharmony_ci le16_to_cpu(desc->life_time), 132162306a36Sopenharmony_ci desc->wl128x_mem.total_mem_blocks, 132262306a36Sopenharmony_ci desc->wl128x_mem.extra_bytes); 132362306a36Sopenharmony_ci } else { 132462306a36Sopenharmony_ci /* calculate number of padding bytes */ 132562306a36Sopenharmony_ci int pad = aligned_len - skb->len; 132662306a36Sopenharmony_ci desc->tx_attr |= 132762306a36Sopenharmony_ci cpu_to_le16(pad << TX_HW_ATTR_OFST_LAST_WORD_PAD); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci /* Store the aligned length in terms of words */ 133062306a36Sopenharmony_ci desc->length = cpu_to_le16(aligned_len >> 2); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci wl1271_debug(DEBUG_TX, 133362306a36Sopenharmony_ci "tx_fill_hdr: pad: %d hlid: %d len: %d life: %d mem: %d", 133462306a36Sopenharmony_ci pad, desc->hlid, 133562306a36Sopenharmony_ci le16_to_cpu(desc->length), 133662306a36Sopenharmony_ci le16_to_cpu(desc->life_time), 133762306a36Sopenharmony_ci desc->wl127x_mem.total_mem_blocks); 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic enum wl_rx_buf_align 134262306a36Sopenharmony_ciwl12xx_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) 134362306a36Sopenharmony_ci{ 134462306a36Sopenharmony_ci if (rx_desc & RX_BUF_UNALIGNED_PAYLOAD) 134562306a36Sopenharmony_ci return WLCORE_RX_BUF_UNALIGNED; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci return WLCORE_RX_BUF_ALIGNED; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data, 135162306a36Sopenharmony_ci u32 data_len) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct wl1271_rx_descriptor *desc = rx_data; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* invalid packet */ 135662306a36Sopenharmony_ci if (data_len < sizeof(*desc) || 135762306a36Sopenharmony_ci data_len < sizeof(*desc) + desc->pad_len) 135862306a36Sopenharmony_ci return 0; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci return data_len - sizeof(*desc) - desc->pad_len; 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_cistatic int wl12xx_tx_delayed_compl(struct wl1271 *wl) 136462306a36Sopenharmony_ci{ 136562306a36Sopenharmony_ci if (wl->fw_status->tx_results_counter == 136662306a36Sopenharmony_ci (wl->tx_results_count & 0xff)) 136762306a36Sopenharmony_ci return 0; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci return wlcore_tx_complete(wl); 137062306a36Sopenharmony_ci} 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_cistatic int wl12xx_hw_init(struct wl1271 *wl) 137362306a36Sopenharmony_ci{ 137462306a36Sopenharmony_ci int ret; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (wl->chip.id == CHIP_ID_128X_PG20) { 137762306a36Sopenharmony_ci u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ret = wl128x_cmd_general_parms(wl); 138062306a36Sopenharmony_ci if (ret < 0) 138162306a36Sopenharmony_ci goto out; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci /* 138462306a36Sopenharmony_ci * If we are in calibrator based auto detect then we got the FEM nr 138562306a36Sopenharmony_ci * in wl->fem_manuf. No need to continue further 138662306a36Sopenharmony_ci */ 138762306a36Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 138862306a36Sopenharmony_ci goto out; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci ret = wl128x_cmd_radio_parms(wl); 139162306a36Sopenharmony_ci if (ret < 0) 139262306a36Sopenharmony_ci goto out; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci if (wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN) 139562306a36Sopenharmony_ci /* Enable SDIO padding */ 139662306a36Sopenharmony_ci host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci /* Must be before wl1271_acx_init_mem_config() */ 139962306a36Sopenharmony_ci ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); 140062306a36Sopenharmony_ci if (ret < 0) 140162306a36Sopenharmony_ci goto out; 140262306a36Sopenharmony_ci } else { 140362306a36Sopenharmony_ci ret = wl1271_cmd_general_parms(wl); 140462306a36Sopenharmony_ci if (ret < 0) 140562306a36Sopenharmony_ci goto out; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* 140862306a36Sopenharmony_ci * If we are in calibrator based auto detect then we got the FEM nr 140962306a36Sopenharmony_ci * in wl->fem_manuf. No need to continue further 141062306a36Sopenharmony_ci */ 141162306a36Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 141262306a36Sopenharmony_ci goto out; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci ret = wl1271_cmd_radio_parms(wl); 141562306a36Sopenharmony_ci if (ret < 0) 141662306a36Sopenharmony_ci goto out; 141762306a36Sopenharmony_ci ret = wl1271_cmd_ext_radio_parms(wl); 141862306a36Sopenharmony_ci if (ret < 0) 141962306a36Sopenharmony_ci goto out; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ciout: 142262306a36Sopenharmony_ci return ret; 142362306a36Sopenharmony_ci} 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_cistatic void wl12xx_convert_fw_status(struct wl1271 *wl, void *raw_fw_status, 142662306a36Sopenharmony_ci struct wl_fw_status *fw_status) 142762306a36Sopenharmony_ci{ 142862306a36Sopenharmony_ci struct wl12xx_fw_status *int_fw_status = raw_fw_status; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci fw_status->intr = le32_to_cpu(int_fw_status->intr); 143162306a36Sopenharmony_ci fw_status->fw_rx_counter = int_fw_status->fw_rx_counter; 143262306a36Sopenharmony_ci fw_status->drv_rx_counter = int_fw_status->drv_rx_counter; 143362306a36Sopenharmony_ci fw_status->tx_results_counter = int_fw_status->tx_results_counter; 143462306a36Sopenharmony_ci fw_status->rx_pkt_descs = int_fw_status->rx_pkt_descs; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci fw_status->fw_localtime = le32_to_cpu(int_fw_status->fw_localtime); 143762306a36Sopenharmony_ci fw_status->link_ps_bitmap = le32_to_cpu(int_fw_status->link_ps_bitmap); 143862306a36Sopenharmony_ci fw_status->link_fast_bitmap = 143962306a36Sopenharmony_ci le32_to_cpu(int_fw_status->link_fast_bitmap); 144062306a36Sopenharmony_ci fw_status->total_released_blks = 144162306a36Sopenharmony_ci le32_to_cpu(int_fw_status->total_released_blks); 144262306a36Sopenharmony_ci fw_status->tx_total = le32_to_cpu(int_fw_status->tx_total); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci fw_status->counters.tx_released_pkts = 144562306a36Sopenharmony_ci int_fw_status->counters.tx_released_pkts; 144662306a36Sopenharmony_ci fw_status->counters.tx_lnk_free_pkts = 144762306a36Sopenharmony_ci int_fw_status->counters.tx_lnk_free_pkts; 144862306a36Sopenharmony_ci fw_status->counters.tx_voice_released_blks = 144962306a36Sopenharmony_ci int_fw_status->counters.tx_voice_released_blks; 145062306a36Sopenharmony_ci fw_status->counters.tx_last_rate = 145162306a36Sopenharmony_ci int_fw_status->counters.tx_last_rate; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci fw_status->log_start_addr = le32_to_cpu(int_fw_status->log_start_addr); 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_cistatic u32 wl12xx_sta_get_ap_rate_mask(struct wl1271 *wl, 145762306a36Sopenharmony_ci struct wl12xx_vif *wlvif) 145862306a36Sopenharmony_ci{ 145962306a36Sopenharmony_ci return wlvif->rate_set; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic void wl12xx_conf_init(struct wl1271 *wl) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci /* apply driver default configuration */ 146762306a36Sopenharmony_ci memcpy(&wl->conf, &wl12xx_conf, sizeof(wl12xx_conf)); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci /* apply default private configuration */ 147062306a36Sopenharmony_ci memcpy(&priv->conf, &wl12xx_default_priv_conf, sizeof(priv->conf)); 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_cistatic bool wl12xx_mac_in_fuse(struct wl1271 *wl) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci bool supported = false; 147662306a36Sopenharmony_ci u8 major, minor; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci if (wl->chip.id == CHIP_ID_128X_PG20) { 147962306a36Sopenharmony_ci major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver); 148062306a36Sopenharmony_ci minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci /* in wl128x we have the MAC address if the PG is >= (2, 1) */ 148362306a36Sopenharmony_ci if (major > 2 || (major == 2 && minor >= 1)) 148462306a36Sopenharmony_ci supported = true; 148562306a36Sopenharmony_ci } else { 148662306a36Sopenharmony_ci major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver); 148762306a36Sopenharmony_ci minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci /* in wl127x we have the MAC address if the PG is >= (3, 1) */ 149062306a36Sopenharmony_ci if (major == 3 && minor >= 1) 149162306a36Sopenharmony_ci supported = true; 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci wl1271_debug(DEBUG_PROBE, 149562306a36Sopenharmony_ci "PG Ver major = %d minor = %d, MAC %s present", 149662306a36Sopenharmony_ci major, minor, supported ? "is" : "is not"); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci return supported; 149962306a36Sopenharmony_ci} 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cistatic int wl12xx_get_fuse_mac(struct wl1271 *wl) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci u32 mac1, mac2; 150462306a36Sopenharmony_ci int ret; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* Device may be in ELP from the bootloader or kexec */ 150762306a36Sopenharmony_ci ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); 150862306a36Sopenharmony_ci if (ret < 0) 150962306a36Sopenharmony_ci goto out; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci usleep_range(500000, 700000); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); 151462306a36Sopenharmony_ci if (ret < 0) 151562306a36Sopenharmony_ci goto out; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1, &mac1); 151862306a36Sopenharmony_ci if (ret < 0) 151962306a36Sopenharmony_ci goto out; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2, &mac2); 152262306a36Sopenharmony_ci if (ret < 0) 152362306a36Sopenharmony_ci goto out; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci /* these are the two parts of the BD_ADDR */ 152662306a36Sopenharmony_ci wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + 152762306a36Sopenharmony_ci ((mac1 & 0xff000000) >> 24); 152862306a36Sopenharmony_ci wl->fuse_nic_addr = mac1 & 0xffffff; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ciout: 153362306a36Sopenharmony_ci return ret; 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci u16 die_info; 153962306a36Sopenharmony_ci int ret; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci if (wl->chip.id == CHIP_ID_128X_PG20) 154262306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1, 154362306a36Sopenharmony_ci &die_info); 154462306a36Sopenharmony_ci else 154562306a36Sopenharmony_ci ret = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1, 154662306a36Sopenharmony_ci &die_info); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci if (ret >= 0 && ver) 154962306a36Sopenharmony_ci *ver = (s8)((die_info & PG_VER_MASK) >> PG_VER_OFFSET); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci return ret; 155262306a36Sopenharmony_ci} 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_cistatic int wl12xx_get_mac(struct wl1271 *wl) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci if (wl12xx_mac_in_fuse(wl)) 155762306a36Sopenharmony_ci return wl12xx_get_fuse_mac(wl); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci return 0; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic void wl12xx_set_tx_desc_csum(struct wl1271 *wl, 156362306a36Sopenharmony_ci struct wl1271_tx_hw_descr *desc, 156462306a36Sopenharmony_ci struct sk_buff *skb) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci desc->wl12xx_reserved = 0; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic int wl12xx_plt_init(struct wl1271 *wl) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci int ret; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci ret = wl->ops->boot(wl); 157462306a36Sopenharmony_ci if (ret < 0) 157562306a36Sopenharmony_ci goto out; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci ret = wl->ops->hw_init(wl); 157862306a36Sopenharmony_ci if (ret < 0) 157962306a36Sopenharmony_ci goto out_irq_disable; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci /* 158262306a36Sopenharmony_ci * If we are in calibrator based auto detect then we got the FEM nr 158362306a36Sopenharmony_ci * in wl->fem_manuf. No need to continue further 158462306a36Sopenharmony_ci */ 158562306a36Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 158662306a36Sopenharmony_ci goto out; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci ret = wl1271_acx_init_mem_config(wl); 158962306a36Sopenharmony_ci if (ret < 0) 159062306a36Sopenharmony_ci goto out_irq_disable; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci ret = wl12xx_acx_mem_cfg(wl); 159362306a36Sopenharmony_ci if (ret < 0) 159462306a36Sopenharmony_ci goto out_free_memmap; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci /* Enable data path */ 159762306a36Sopenharmony_ci ret = wl1271_cmd_data_path(wl, 1); 159862306a36Sopenharmony_ci if (ret < 0) 159962306a36Sopenharmony_ci goto out_free_memmap; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* Configure for CAM power saving (ie. always active) */ 160262306a36Sopenharmony_ci ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); 160362306a36Sopenharmony_ci if (ret < 0) 160462306a36Sopenharmony_ci goto out_free_memmap; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* configure PM */ 160762306a36Sopenharmony_ci ret = wl1271_acx_pm_config(wl); 160862306a36Sopenharmony_ci if (ret < 0) 160962306a36Sopenharmony_ci goto out_free_memmap; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci goto out; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ciout_free_memmap: 161462306a36Sopenharmony_ci kfree(wl->target_mem_map); 161562306a36Sopenharmony_ci wl->target_mem_map = NULL; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ciout_irq_disable: 161862306a36Sopenharmony_ci mutex_unlock(&wl->mutex); 161962306a36Sopenharmony_ci /* Unlocking the mutex in the middle of handling is 162062306a36Sopenharmony_ci inherently unsafe. In this case we deem it safe to do, 162162306a36Sopenharmony_ci because we need to let any possibly pending IRQ out of 162262306a36Sopenharmony_ci the system (and while we are WL1271_STATE_OFF the IRQ 162362306a36Sopenharmony_ci work function will not do anything.) Also, any other 162462306a36Sopenharmony_ci possible concurrent operations will fail due to the 162562306a36Sopenharmony_ci current state, hence the wl1271 struct should be safe. */ 162662306a36Sopenharmony_ci wlcore_disable_interrupts(wl); 162762306a36Sopenharmony_ci mutex_lock(&wl->mutex); 162862306a36Sopenharmony_ciout: 162962306a36Sopenharmony_ci return ret; 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_cistatic int wl12xx_get_spare_blocks(struct wl1271 *wl, bool is_gem) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci if (is_gem) 163562306a36Sopenharmony_ci return WL12XX_TX_HW_BLOCK_GEM_SPARE; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci return WL12XX_TX_HW_BLOCK_SPARE_DEFAULT; 163862306a36Sopenharmony_ci} 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_cistatic int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd, 164162306a36Sopenharmony_ci struct ieee80211_vif *vif, 164262306a36Sopenharmony_ci struct ieee80211_sta *sta, 164362306a36Sopenharmony_ci struct ieee80211_key_conf *key_conf) 164462306a36Sopenharmony_ci{ 164562306a36Sopenharmony_ci return wlcore_set_key(wl, cmd, vif, sta, key_conf); 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_cistatic int wl12xx_set_peer_cap(struct wl1271 *wl, 164962306a36Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap, 165062306a36Sopenharmony_ci bool allow_ht_operation, 165162306a36Sopenharmony_ci u32 rate_set, u8 hlid) 165262306a36Sopenharmony_ci{ 165362306a36Sopenharmony_ci return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation, 165462306a36Sopenharmony_ci hlid); 165562306a36Sopenharmony_ci} 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_cistatic bool wl12xx_lnk_high_prio(struct wl1271 *wl, u8 hlid, 165862306a36Sopenharmony_ci struct wl1271_link *lnk) 165962306a36Sopenharmony_ci{ 166062306a36Sopenharmony_ci u8 thold; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci if (test_bit(hlid, &wl->fw_fast_lnk_map)) 166362306a36Sopenharmony_ci thold = wl->conf.tx.fast_link_thold; 166462306a36Sopenharmony_ci else 166562306a36Sopenharmony_ci thold = wl->conf.tx.slow_link_thold; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci return lnk->allocated_pkts < thold; 166862306a36Sopenharmony_ci} 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_cistatic bool wl12xx_lnk_low_prio(struct wl1271 *wl, u8 hlid, 167162306a36Sopenharmony_ci struct wl1271_link *lnk) 167262306a36Sopenharmony_ci{ 167362306a36Sopenharmony_ci /* any link is good for low priority */ 167462306a36Sopenharmony_ci return true; 167562306a36Sopenharmony_ci} 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_cistatic u32 wl12xx_convert_hwaddr(struct wl1271 *wl, u32 hwaddr) 167862306a36Sopenharmony_ci{ 167962306a36Sopenharmony_ci return hwaddr << 5; 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_cistatic int wl12xx_setup(struct wl1271 *wl); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_cistatic struct wlcore_ops wl12xx_ops = { 168562306a36Sopenharmony_ci .setup = wl12xx_setup, 168662306a36Sopenharmony_ci .identify_chip = wl12xx_identify_chip, 168762306a36Sopenharmony_ci .boot = wl12xx_boot, 168862306a36Sopenharmony_ci .plt_init = wl12xx_plt_init, 168962306a36Sopenharmony_ci .trigger_cmd = wl12xx_trigger_cmd, 169062306a36Sopenharmony_ci .ack_event = wl12xx_ack_event, 169162306a36Sopenharmony_ci .wait_for_event = wl12xx_wait_for_event, 169262306a36Sopenharmony_ci .process_mailbox_events = wl12xx_process_mailbox_events, 169362306a36Sopenharmony_ci .calc_tx_blocks = wl12xx_calc_tx_blocks, 169462306a36Sopenharmony_ci .set_tx_desc_blocks = wl12xx_set_tx_desc_blocks, 169562306a36Sopenharmony_ci .set_tx_desc_data_len = wl12xx_set_tx_desc_data_len, 169662306a36Sopenharmony_ci .get_rx_buf_align = wl12xx_get_rx_buf_align, 169762306a36Sopenharmony_ci .get_rx_packet_len = wl12xx_get_rx_packet_len, 169862306a36Sopenharmony_ci .tx_immediate_compl = NULL, 169962306a36Sopenharmony_ci .tx_delayed_compl = wl12xx_tx_delayed_compl, 170062306a36Sopenharmony_ci .hw_init = wl12xx_hw_init, 170162306a36Sopenharmony_ci .init_vif = NULL, 170262306a36Sopenharmony_ci .convert_fw_status = wl12xx_convert_fw_status, 170362306a36Sopenharmony_ci .sta_get_ap_rate_mask = wl12xx_sta_get_ap_rate_mask, 170462306a36Sopenharmony_ci .get_pg_ver = wl12xx_get_pg_ver, 170562306a36Sopenharmony_ci .get_mac = wl12xx_get_mac, 170662306a36Sopenharmony_ci .set_tx_desc_csum = wl12xx_set_tx_desc_csum, 170762306a36Sopenharmony_ci .set_rx_csum = NULL, 170862306a36Sopenharmony_ci .ap_get_mimo_wide_rate_mask = NULL, 170962306a36Sopenharmony_ci .debugfs_init = wl12xx_debugfs_add_files, 171062306a36Sopenharmony_ci .scan_start = wl12xx_scan_start, 171162306a36Sopenharmony_ci .scan_stop = wl12xx_scan_stop, 171262306a36Sopenharmony_ci .sched_scan_start = wl12xx_sched_scan_start, 171362306a36Sopenharmony_ci .sched_scan_stop = wl12xx_scan_sched_scan_stop, 171462306a36Sopenharmony_ci .get_spare_blocks = wl12xx_get_spare_blocks, 171562306a36Sopenharmony_ci .set_key = wl12xx_set_key, 171662306a36Sopenharmony_ci .channel_switch = wl12xx_cmd_channel_switch, 171762306a36Sopenharmony_ci .pre_pkt_send = NULL, 171862306a36Sopenharmony_ci .set_peer_cap = wl12xx_set_peer_cap, 171962306a36Sopenharmony_ci .convert_hwaddr = wl12xx_convert_hwaddr, 172062306a36Sopenharmony_ci .lnk_high_prio = wl12xx_lnk_high_prio, 172162306a36Sopenharmony_ci .lnk_low_prio = wl12xx_lnk_low_prio, 172262306a36Sopenharmony_ci .interrupt_notify = NULL, 172362306a36Sopenharmony_ci .rx_ba_filter = NULL, 172462306a36Sopenharmony_ci .ap_sleep = NULL, 172562306a36Sopenharmony_ci}; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic struct ieee80211_sta_ht_cap wl12xx_ht_cap = { 172862306a36Sopenharmony_ci .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | 172962306a36Sopenharmony_ci (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), 173062306a36Sopenharmony_ci .ht_supported = true, 173162306a36Sopenharmony_ci .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, 173262306a36Sopenharmony_ci .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, 173362306a36Sopenharmony_ci .mcs = { 173462306a36Sopenharmony_ci .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, 173562306a36Sopenharmony_ci .rx_highest = cpu_to_le16(72), 173662306a36Sopenharmony_ci .tx_params = IEEE80211_HT_MCS_TX_DEFINED, 173762306a36Sopenharmony_ci }, 173862306a36Sopenharmony_ci}; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_cistatic const struct ieee80211_iface_limit wl12xx_iface_limits[] = { 174162306a36Sopenharmony_ci { 174262306a36Sopenharmony_ci .max = 3, 174362306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION), 174462306a36Sopenharmony_ci }, 174562306a36Sopenharmony_ci { 174662306a36Sopenharmony_ci .max = 1, 174762306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP) | 174862306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) | 174962306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT), 175062306a36Sopenharmony_ci }, 175162306a36Sopenharmony_ci}; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cistatic const struct ieee80211_iface_combination 175462306a36Sopenharmony_ciwl12xx_iface_combinations[] = { 175562306a36Sopenharmony_ci { 175662306a36Sopenharmony_ci .max_interfaces = 3, 175762306a36Sopenharmony_ci .limits = wl12xx_iface_limits, 175862306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(wl12xx_iface_limits), 175962306a36Sopenharmony_ci .num_different_channels = 1, 176062306a36Sopenharmony_ci }, 176162306a36Sopenharmony_ci}; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_cistatic const struct wl12xx_clock wl12xx_refclock_table[] = { 176462306a36Sopenharmony_ci { 19200000, false, WL12XX_REFCLOCK_19 }, 176562306a36Sopenharmony_ci { 26000000, false, WL12XX_REFCLOCK_26 }, 176662306a36Sopenharmony_ci { 26000000, true, WL12XX_REFCLOCK_26_XTAL }, 176762306a36Sopenharmony_ci { 38400000, false, WL12XX_REFCLOCK_38 }, 176862306a36Sopenharmony_ci { 38400000, true, WL12XX_REFCLOCK_38_XTAL }, 176962306a36Sopenharmony_ci { 52000000, false, WL12XX_REFCLOCK_52 }, 177062306a36Sopenharmony_ci { 0, false, 0 } 177162306a36Sopenharmony_ci}; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_cistatic const struct wl12xx_clock wl12xx_tcxoclock_table[] = { 177462306a36Sopenharmony_ci { 16368000, true, WL12XX_TCXOCLOCK_16_368 }, 177562306a36Sopenharmony_ci { 16800000, true, WL12XX_TCXOCLOCK_16_8 }, 177662306a36Sopenharmony_ci { 19200000, true, WL12XX_TCXOCLOCK_19_2 }, 177762306a36Sopenharmony_ci { 26000000, true, WL12XX_TCXOCLOCK_26 }, 177862306a36Sopenharmony_ci { 32736000, true, WL12XX_TCXOCLOCK_32_736 }, 177962306a36Sopenharmony_ci { 33600000, true, WL12XX_TCXOCLOCK_33_6 }, 178062306a36Sopenharmony_ci { 38400000, true, WL12XX_TCXOCLOCK_38_4 }, 178162306a36Sopenharmony_ci { 52000000, true, WL12XX_TCXOCLOCK_52 }, 178262306a36Sopenharmony_ci { 0, false, 0 } 178362306a36Sopenharmony_ci}; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_cistatic int wl12xx_get_clock_idx(const struct wl12xx_clock *table, 178662306a36Sopenharmony_ci u32 freq, bool xtal) 178762306a36Sopenharmony_ci{ 178862306a36Sopenharmony_ci int i; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci for (i = 0; table[i].freq != 0; i++) 179162306a36Sopenharmony_ci if ((table[i].freq == freq) && (table[i].xtal == xtal)) 179262306a36Sopenharmony_ci return table[i].hw_idx; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci return -EINVAL; 179562306a36Sopenharmony_ci} 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cistatic int wl12xx_setup(struct wl1271 *wl) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 180062306a36Sopenharmony_ci struct wlcore_platdev_data *pdev_data = dev_get_platdata(&wl->pdev->dev); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci BUILD_BUG_ON(WL12XX_MAX_LINKS > WLCORE_MAX_LINKS); 180362306a36Sopenharmony_ci BUILD_BUG_ON(WL12XX_MAX_AP_STATIONS > WL12XX_MAX_LINKS); 180462306a36Sopenharmony_ci BUILD_BUG_ON(WL12XX_CONF_SG_PARAMS_MAX > WLCORE_CONF_SG_PARAMS_MAX); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci wl->rtable = wl12xx_rtable; 180762306a36Sopenharmony_ci wl->num_tx_desc = WL12XX_NUM_TX_DESCRIPTORS; 180862306a36Sopenharmony_ci wl->num_rx_desc = WL12XX_NUM_RX_DESCRIPTORS; 180962306a36Sopenharmony_ci wl->num_links = WL12XX_MAX_LINKS; 181062306a36Sopenharmony_ci wl->max_ap_stations = WL12XX_MAX_AP_STATIONS; 181162306a36Sopenharmony_ci wl->iface_combinations = wl12xx_iface_combinations; 181262306a36Sopenharmony_ci wl->n_iface_combinations = ARRAY_SIZE(wl12xx_iface_combinations); 181362306a36Sopenharmony_ci wl->num_mac_addr = WL12XX_NUM_MAC_ADDRESSES; 181462306a36Sopenharmony_ci wl->band_rate_to_idx = wl12xx_band_rate_to_idx; 181562306a36Sopenharmony_ci wl->hw_tx_rate_tbl_size = WL12XX_CONF_HW_RXTX_RATE_MAX; 181662306a36Sopenharmony_ci wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0; 181762306a36Sopenharmony_ci wl->fw_status_len = sizeof(struct wl12xx_fw_status); 181862306a36Sopenharmony_ci wl->fw_status_priv_len = 0; 181962306a36Sopenharmony_ci wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics); 182062306a36Sopenharmony_ci wl->ofdm_only_ap = true; 182162306a36Sopenharmony_ci wlcore_set_ht_cap(wl, NL80211_BAND_2GHZ, &wl12xx_ht_cap); 182262306a36Sopenharmony_ci wlcore_set_ht_cap(wl, NL80211_BAND_5GHZ, &wl12xx_ht_cap); 182362306a36Sopenharmony_ci wl12xx_conf_init(wl); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci if (!fref_param) { 182662306a36Sopenharmony_ci priv->ref_clock = wl12xx_get_clock_idx(wl12xx_refclock_table, 182762306a36Sopenharmony_ci pdev_data->ref_clock_freq, 182862306a36Sopenharmony_ci pdev_data->ref_clock_xtal); 182962306a36Sopenharmony_ci if (priv->ref_clock < 0) { 183062306a36Sopenharmony_ci wl1271_error("Invalid ref_clock frequency (%d Hz, %s)", 183162306a36Sopenharmony_ci pdev_data->ref_clock_freq, 183262306a36Sopenharmony_ci pdev_data->ref_clock_xtal ? 183362306a36Sopenharmony_ci "XTAL" : "not XTAL"); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci return priv->ref_clock; 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci } else { 183862306a36Sopenharmony_ci if (!strcmp(fref_param, "19.2")) 183962306a36Sopenharmony_ci priv->ref_clock = WL12XX_REFCLOCK_19; 184062306a36Sopenharmony_ci else if (!strcmp(fref_param, "26")) 184162306a36Sopenharmony_ci priv->ref_clock = WL12XX_REFCLOCK_26; 184262306a36Sopenharmony_ci else if (!strcmp(fref_param, "26x")) 184362306a36Sopenharmony_ci priv->ref_clock = WL12XX_REFCLOCK_26_XTAL; 184462306a36Sopenharmony_ci else if (!strcmp(fref_param, "38.4")) 184562306a36Sopenharmony_ci priv->ref_clock = WL12XX_REFCLOCK_38; 184662306a36Sopenharmony_ci else if (!strcmp(fref_param, "38.4x")) 184762306a36Sopenharmony_ci priv->ref_clock = WL12XX_REFCLOCK_38_XTAL; 184862306a36Sopenharmony_ci else if (!strcmp(fref_param, "52")) 184962306a36Sopenharmony_ci priv->ref_clock = WL12XX_REFCLOCK_52; 185062306a36Sopenharmony_ci else 185162306a36Sopenharmony_ci wl1271_error("Invalid fref parameter %s", fref_param); 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (!tcxo_param && pdev_data->tcxo_clock_freq) { 185562306a36Sopenharmony_ci priv->tcxo_clock = wl12xx_get_clock_idx(wl12xx_tcxoclock_table, 185662306a36Sopenharmony_ci pdev_data->tcxo_clock_freq, 185762306a36Sopenharmony_ci true); 185862306a36Sopenharmony_ci if (priv->tcxo_clock < 0) { 185962306a36Sopenharmony_ci wl1271_error("Invalid tcxo_clock frequency (%d Hz)", 186062306a36Sopenharmony_ci pdev_data->tcxo_clock_freq); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci return priv->tcxo_clock; 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci } else if (tcxo_param) { 186562306a36Sopenharmony_ci if (!strcmp(tcxo_param, "19.2")) 186662306a36Sopenharmony_ci priv->tcxo_clock = WL12XX_TCXOCLOCK_19_2; 186762306a36Sopenharmony_ci else if (!strcmp(tcxo_param, "26")) 186862306a36Sopenharmony_ci priv->tcxo_clock = WL12XX_TCXOCLOCK_26; 186962306a36Sopenharmony_ci else if (!strcmp(tcxo_param, "38.4")) 187062306a36Sopenharmony_ci priv->tcxo_clock = WL12XX_TCXOCLOCK_38_4; 187162306a36Sopenharmony_ci else if (!strcmp(tcxo_param, "52")) 187262306a36Sopenharmony_ci priv->tcxo_clock = WL12XX_TCXOCLOCK_52; 187362306a36Sopenharmony_ci else if (!strcmp(tcxo_param, "16.368")) 187462306a36Sopenharmony_ci priv->tcxo_clock = WL12XX_TCXOCLOCK_16_368; 187562306a36Sopenharmony_ci else if (!strcmp(tcxo_param, "32.736")) 187662306a36Sopenharmony_ci priv->tcxo_clock = WL12XX_TCXOCLOCK_32_736; 187762306a36Sopenharmony_ci else if (!strcmp(tcxo_param, "16.8")) 187862306a36Sopenharmony_ci priv->tcxo_clock = WL12XX_TCXOCLOCK_16_8; 187962306a36Sopenharmony_ci else if (!strcmp(tcxo_param, "33.6")) 188062306a36Sopenharmony_ci priv->tcxo_clock = WL12XX_TCXOCLOCK_33_6; 188162306a36Sopenharmony_ci else 188262306a36Sopenharmony_ci wl1271_error("Invalid tcxo parameter %s", tcxo_param); 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci priv->rx_mem_addr = kmalloc(sizeof(*priv->rx_mem_addr), GFP_KERNEL); 188662306a36Sopenharmony_ci if (!priv->rx_mem_addr) 188762306a36Sopenharmony_ci return -ENOMEM; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci return 0; 189062306a36Sopenharmony_ci} 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_cistatic int wl12xx_probe(struct platform_device *pdev) 189362306a36Sopenharmony_ci{ 189462306a36Sopenharmony_ci struct wl1271 *wl; 189562306a36Sopenharmony_ci struct ieee80211_hw *hw; 189662306a36Sopenharmony_ci int ret; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci hw = wlcore_alloc_hw(sizeof(struct wl12xx_priv), 189962306a36Sopenharmony_ci WL12XX_AGGR_BUFFER_SIZE, 190062306a36Sopenharmony_ci sizeof(struct wl12xx_event_mailbox)); 190162306a36Sopenharmony_ci if (IS_ERR(hw)) { 190262306a36Sopenharmony_ci wl1271_error("can't allocate hw"); 190362306a36Sopenharmony_ci ret = PTR_ERR(hw); 190462306a36Sopenharmony_ci goto out; 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci wl = hw->priv; 190862306a36Sopenharmony_ci wl->ops = &wl12xx_ops; 190962306a36Sopenharmony_ci wl->ptable = wl12xx_ptable; 191062306a36Sopenharmony_ci ret = wlcore_probe(wl, pdev); 191162306a36Sopenharmony_ci if (ret) 191262306a36Sopenharmony_ci goto out_free; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci return ret; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ciout_free: 191762306a36Sopenharmony_ci wlcore_free_hw(wl); 191862306a36Sopenharmony_ciout: 191962306a36Sopenharmony_ci return ret; 192062306a36Sopenharmony_ci} 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_cistatic int wl12xx_remove(struct platform_device *pdev) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci struct wl1271 *wl = platform_get_drvdata(pdev); 192562306a36Sopenharmony_ci struct wl12xx_priv *priv; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci priv = wl->priv; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci kfree(priv->rx_mem_addr); 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci return wlcore_remove(pdev); 193262306a36Sopenharmony_ci} 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_cistatic const struct platform_device_id wl12xx_id_table[] = { 193562306a36Sopenharmony_ci { "wl12xx", 0 }, 193662306a36Sopenharmony_ci { } /* Terminating Entry */ 193762306a36Sopenharmony_ci}; 193862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, wl12xx_id_table); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_cistatic struct platform_driver wl12xx_driver = { 194162306a36Sopenharmony_ci .probe = wl12xx_probe, 194262306a36Sopenharmony_ci .remove = wl12xx_remove, 194362306a36Sopenharmony_ci .id_table = wl12xx_id_table, 194462306a36Sopenharmony_ci .driver = { 194562306a36Sopenharmony_ci .name = "wl12xx_driver", 194662306a36Sopenharmony_ci } 194762306a36Sopenharmony_ci}; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_cimodule_platform_driver(wl12xx_driver); 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_cimodule_param_named(fref, fref_param, charp, 0); 195262306a36Sopenharmony_ciMODULE_PARM_DESC(fref, "FREF clock: 19.2, 26, 26x, 38.4, 38.4x, 52"); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_cimodule_param_named(tcxo, tcxo_param, charp, 0); 195562306a36Sopenharmony_ciMODULE_PARM_DESC(tcxo, 195662306a36Sopenharmony_ci "TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6"); 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 195962306a36Sopenharmony_ciMODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); 196062306a36Sopenharmony_ciMODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); 196162306a36Sopenharmony_ciMODULE_FIRMWARE(WL127X_FW_NAME_MULTI); 196262306a36Sopenharmony_ciMODULE_FIRMWARE(WL127X_PLT_FW_NAME); 196362306a36Sopenharmony_ciMODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); 196462306a36Sopenharmony_ciMODULE_FIRMWARE(WL128X_FW_NAME_MULTI); 196562306a36Sopenharmony_ciMODULE_FIRMWARE(WL128X_PLT_FW_NAME); 1966