162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file is part of wl12xx 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009-2010 Nokia Corporation 662306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments Inc. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "../wlcore/cmd.h" 1062306a36Sopenharmony_ci#include "../wlcore/debug.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "wl12xx.h" 1362306a36Sopenharmony_ci#include "cmd.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciint wl1271_cmd_ext_radio_parms(struct wl1271 *wl) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct wl1271_ext_radio_parms_cmd *ext_radio_parms; 1862306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 1962306a36Sopenharmony_ci struct wl12xx_conf_rf *rf = &priv->conf.rf; 2062306a36Sopenharmony_ci int ret; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci if (!wl->nvs) 2362306a36Sopenharmony_ci return -ENODEV; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); 2662306a36Sopenharmony_ci if (!ext_radio_parms) 2762306a36Sopenharmony_ci return -ENOMEM; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, 3262306a36Sopenharmony_ci rf->tx_per_channel_power_compensation_2, 3362306a36Sopenharmony_ci CONF_TX_PWR_COMPENSATION_LEN_2); 3462306a36Sopenharmony_ci memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, 3562306a36Sopenharmony_ci rf->tx_per_channel_power_compensation_5, 3662306a36Sopenharmony_ci CONF_TX_PWR_COMPENSATION_LEN_5); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", 3962306a36Sopenharmony_ci ext_radio_parms, sizeof(*ext_radio_parms)); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); 4262306a36Sopenharmony_ci if (ret < 0) 4362306a36Sopenharmony_ci wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci kfree(ext_radio_parms); 4662306a36Sopenharmony_ci return ret; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciint wl1271_cmd_general_parms(struct wl1271 *wl) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct wl1271_general_parms_cmd *gen_parms; 5262306a36Sopenharmony_ci struct wl1271_ini_general_params *gp = 5362306a36Sopenharmony_ci &((struct wl1271_nvs_file *)wl->nvs)->general_params; 5462306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 5562306a36Sopenharmony_ci bool answer = false; 5662306a36Sopenharmony_ci int ret; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (!wl->nvs) 5962306a36Sopenharmony_ci return -ENODEV; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 6262306a36Sopenharmony_ci wl1271_warning("FEM index from INI out of bounds"); 6362306a36Sopenharmony_ci return -EINVAL; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); 6762306a36Sopenharmony_ci if (!gen_parms) 6862306a36Sopenharmony_ci return -ENOMEM; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci memcpy(&gen_parms->general_params, gp, sizeof(*gp)); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* If we started in PLT FEM_DETECT mode, force auto detect */ 7562306a36Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 7662306a36Sopenharmony_ci gen_parms->general_params.tx_bip_fem_auto_detect = true; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (gen_parms->general_params.tx_bip_fem_auto_detect) 7962306a36Sopenharmony_ci answer = true; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* Override the REF CLK from the NVS with the one from platform data */ 8262306a36Sopenharmony_ci gen_parms->general_params.ref_clock = priv->ref_clock; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); 8562306a36Sopenharmony_ci if (ret < 0) { 8662306a36Sopenharmony_ci wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); 8762306a36Sopenharmony_ci goto out; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci gp->tx_bip_fem_manufacturer = 9162306a36Sopenharmony_ci gen_parms->general_params.tx_bip_fem_manufacturer; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 9462306a36Sopenharmony_ci wl1271_warning("FEM index from FW out of bounds"); 9562306a36Sopenharmony_ci ret = -EINVAL; 9662306a36Sopenharmony_ci goto out; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* If we are in calibrator based fem auto detect - save fem nr */ 10062306a36Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 10162306a36Sopenharmony_ci wl->fem_manuf = gp->tx_bip_fem_manufacturer; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", 10462306a36Sopenharmony_ci answer == false ? 10562306a36Sopenharmony_ci "manual" : 10662306a36Sopenharmony_ci wl->plt_mode == PLT_FEM_DETECT ? 10762306a36Sopenharmony_ci "calibrator_fem_detect" : 10862306a36Sopenharmony_ci "auto", 10962306a36Sopenharmony_ci gp->tx_bip_fem_manufacturer); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciout: 11262306a36Sopenharmony_ci kfree(gen_parms); 11362306a36Sopenharmony_ci return ret; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciint wl128x_cmd_general_parms(struct wl1271 *wl) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct wl128x_general_parms_cmd *gen_parms; 11962306a36Sopenharmony_ci struct wl128x_ini_general_params *gp = 12062306a36Sopenharmony_ci &((struct wl128x_nvs_file *)wl->nvs)->general_params; 12162306a36Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 12262306a36Sopenharmony_ci bool answer = false; 12362306a36Sopenharmony_ci int ret; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (!wl->nvs) 12662306a36Sopenharmony_ci return -ENODEV; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 12962306a36Sopenharmony_ci wl1271_warning("FEM index from ini out of bounds"); 13062306a36Sopenharmony_ci return -EINVAL; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); 13462306a36Sopenharmony_ci if (!gen_parms) 13562306a36Sopenharmony_ci return -ENOMEM; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci memcpy(&gen_parms->general_params, gp, sizeof(*gp)); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* If we started in PLT FEM_DETECT mode, force auto detect */ 14262306a36Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 14362306a36Sopenharmony_ci gen_parms->general_params.tx_bip_fem_auto_detect = true; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (gen_parms->general_params.tx_bip_fem_auto_detect) 14662306a36Sopenharmony_ci answer = true; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* Replace REF and TCXO CLKs with the ones from platform data */ 14962306a36Sopenharmony_ci gen_parms->general_params.ref_clock = priv->ref_clock; 15062306a36Sopenharmony_ci gen_parms->general_params.tcxo_ref_clock = priv->tcxo_clock; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); 15362306a36Sopenharmony_ci if (ret < 0) { 15462306a36Sopenharmony_ci wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); 15562306a36Sopenharmony_ci goto out; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci gp->tx_bip_fem_manufacturer = 15962306a36Sopenharmony_ci gen_parms->general_params.tx_bip_fem_manufacturer; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 16262306a36Sopenharmony_ci wl1271_warning("FEM index from FW out of bounds"); 16362306a36Sopenharmony_ci ret = -EINVAL; 16462306a36Sopenharmony_ci goto out; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* If we are in calibrator based fem auto detect - save fem nr */ 16862306a36Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 16962306a36Sopenharmony_ci wl->fem_manuf = gp->tx_bip_fem_manufacturer; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", 17262306a36Sopenharmony_ci answer == false ? 17362306a36Sopenharmony_ci "manual" : 17462306a36Sopenharmony_ci wl->plt_mode == PLT_FEM_DETECT ? 17562306a36Sopenharmony_ci "calibrator_fem_detect" : 17662306a36Sopenharmony_ci "auto", 17762306a36Sopenharmony_ci gp->tx_bip_fem_manufacturer); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciout: 18062306a36Sopenharmony_ci kfree(gen_parms); 18162306a36Sopenharmony_ci return ret; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ciint wl1271_cmd_radio_parms(struct wl1271 *wl) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; 18762306a36Sopenharmony_ci struct wl1271_radio_parms_cmd *radio_parms; 18862306a36Sopenharmony_ci struct wl1271_ini_general_params *gp = &nvs->general_params; 18962306a36Sopenharmony_ci int ret, fem_idx; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (!wl->nvs) 19262306a36Sopenharmony_ci return -ENODEV; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); 19562306a36Sopenharmony_ci if (!radio_parms) 19662306a36Sopenharmony_ci return -ENOMEM; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* 2.4GHz parameters */ 20362306a36Sopenharmony_ci memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, 20462306a36Sopenharmony_ci sizeof(struct wl1271_ini_band_params_2)); 20562306a36Sopenharmony_ci memcpy(&radio_parms->dyn_params_2, 20662306a36Sopenharmony_ci &nvs->dyn_radio_params_2[fem_idx].params, 20762306a36Sopenharmony_ci sizeof(struct wl1271_ini_fem_params_2)); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* 5GHz parameters */ 21062306a36Sopenharmony_ci memcpy(&radio_parms->static_params_5, 21162306a36Sopenharmony_ci &nvs->stat_radio_params_5, 21262306a36Sopenharmony_ci sizeof(struct wl1271_ini_band_params_5)); 21362306a36Sopenharmony_ci memcpy(&radio_parms->dyn_params_5, 21462306a36Sopenharmony_ci &nvs->dyn_radio_params_5[fem_idx].params, 21562306a36Sopenharmony_ci sizeof(struct wl1271_ini_fem_params_5)); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 21862306a36Sopenharmony_ci radio_parms, sizeof(*radio_parms)); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); 22162306a36Sopenharmony_ci if (ret < 0) 22262306a36Sopenharmony_ci wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci kfree(radio_parms); 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciint wl128x_cmd_radio_parms(struct wl1271 *wl) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; 23162306a36Sopenharmony_ci struct wl128x_radio_parms_cmd *radio_parms; 23262306a36Sopenharmony_ci struct wl128x_ini_general_params *gp = &nvs->general_params; 23362306a36Sopenharmony_ci int ret, fem_idx; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (!wl->nvs) 23662306a36Sopenharmony_ci return -ENODEV; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); 23962306a36Sopenharmony_ci if (!radio_parms) 24062306a36Sopenharmony_ci return -ENOMEM; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* 2.4GHz parameters */ 24762306a36Sopenharmony_ci memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, 24862306a36Sopenharmony_ci sizeof(struct wl128x_ini_band_params_2)); 24962306a36Sopenharmony_ci memcpy(&radio_parms->dyn_params_2, 25062306a36Sopenharmony_ci &nvs->dyn_radio_params_2[fem_idx].params, 25162306a36Sopenharmony_ci sizeof(struct wl128x_ini_fem_params_2)); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 5GHz parameters */ 25462306a36Sopenharmony_ci memcpy(&radio_parms->static_params_5, 25562306a36Sopenharmony_ci &nvs->stat_radio_params_5, 25662306a36Sopenharmony_ci sizeof(struct wl128x_ini_band_params_5)); 25762306a36Sopenharmony_ci memcpy(&radio_parms->dyn_params_5, 25862306a36Sopenharmony_ci &nvs->dyn_radio_params_5[fem_idx].params, 25962306a36Sopenharmony_ci sizeof(struct wl128x_ini_fem_params_5)); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 26462306a36Sopenharmony_ci radio_parms, sizeof(*radio_parms)); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); 26762306a36Sopenharmony_ci if (ret < 0) 26862306a36Sopenharmony_ci wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci kfree(radio_parms); 27162306a36Sopenharmony_ci return ret; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ciint wl12xx_cmd_channel_switch(struct wl1271 *wl, 27562306a36Sopenharmony_ci struct wl12xx_vif *wlvif, 27662306a36Sopenharmony_ci struct ieee80211_channel_switch *ch_switch) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct wl12xx_cmd_channel_switch *cmd; 27962306a36Sopenharmony_ci int ret; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci wl1271_debug(DEBUG_ACX, "cmd channel switch"); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 28462306a36Sopenharmony_ci if (!cmd) { 28562306a36Sopenharmony_ci ret = -ENOMEM; 28662306a36Sopenharmony_ci goto out; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci cmd->role_id = wlvif->role_id; 29062306a36Sopenharmony_ci cmd->channel = ch_switch->chandef.chan->hw_value; 29162306a36Sopenharmony_ci cmd->switch_time = ch_switch->count; 29262306a36Sopenharmony_ci cmd->stop_tx = ch_switch->block_tx; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* FIXME: control from mac80211 in the future */ 29562306a36Sopenharmony_ci /* Enable TX on the target channel */ 29662306a36Sopenharmony_ci cmd->post_switch_tx_disable = 0; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); 29962306a36Sopenharmony_ci if (ret < 0) { 30062306a36Sopenharmony_ci wl1271_error("failed to send channel switch command"); 30162306a36Sopenharmony_ci goto out_free; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ciout_free: 30562306a36Sopenharmony_ci kfree(cmd); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciout: 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci} 310