18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of wl12xx 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009-2010 Nokia Corporation 68c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments Inc. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "../wlcore/cmd.h" 108c2ecf20Sopenharmony_ci#include "../wlcore/debug.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "wl12xx.h" 138c2ecf20Sopenharmony_ci#include "cmd.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciint wl1271_cmd_ext_radio_parms(struct wl1271 *wl) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci struct wl1271_ext_radio_parms_cmd *ext_radio_parms; 188c2ecf20Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 198c2ecf20Sopenharmony_ci struct wl12xx_conf_rf *rf = &priv->conf.rf; 208c2ecf20Sopenharmony_ci int ret; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci if (!wl->nvs) 238c2ecf20Sopenharmony_ci return -ENODEV; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); 268c2ecf20Sopenharmony_ci if (!ext_radio_parms) 278c2ecf20Sopenharmony_ci return -ENOMEM; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, 328c2ecf20Sopenharmony_ci rf->tx_per_channel_power_compensation_2, 338c2ecf20Sopenharmony_ci CONF_TX_PWR_COMPENSATION_LEN_2); 348c2ecf20Sopenharmony_ci memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, 358c2ecf20Sopenharmony_ci rf->tx_per_channel_power_compensation_5, 368c2ecf20Sopenharmony_ci CONF_TX_PWR_COMPENSATION_LEN_5); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", 398c2ecf20Sopenharmony_ci ext_radio_parms, sizeof(*ext_radio_parms)); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); 428c2ecf20Sopenharmony_ci if (ret < 0) 438c2ecf20Sopenharmony_ci wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci kfree(ext_radio_parms); 468c2ecf20Sopenharmony_ci return ret; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciint wl1271_cmd_general_parms(struct wl1271 *wl) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct wl1271_general_parms_cmd *gen_parms; 528c2ecf20Sopenharmony_ci struct wl1271_ini_general_params *gp = 538c2ecf20Sopenharmony_ci &((struct wl1271_nvs_file *)wl->nvs)->general_params; 548c2ecf20Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 558c2ecf20Sopenharmony_ci bool answer = false; 568c2ecf20Sopenharmony_ci int ret; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (!wl->nvs) 598c2ecf20Sopenharmony_ci return -ENODEV; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 628c2ecf20Sopenharmony_ci wl1271_warning("FEM index from INI out of bounds"); 638c2ecf20Sopenharmony_ci return -EINVAL; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); 678c2ecf20Sopenharmony_ci if (!gen_parms) 688c2ecf20Sopenharmony_ci return -ENOMEM; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci memcpy(&gen_parms->general_params, gp, sizeof(*gp)); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* If we started in PLT FEM_DETECT mode, force auto detect */ 758c2ecf20Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 768c2ecf20Sopenharmony_ci gen_parms->general_params.tx_bip_fem_auto_detect = true; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (gen_parms->general_params.tx_bip_fem_auto_detect) 798c2ecf20Sopenharmony_ci answer = true; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* Override the REF CLK from the NVS with the one from platform data */ 828c2ecf20Sopenharmony_ci gen_parms->general_params.ref_clock = priv->ref_clock; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); 858c2ecf20Sopenharmony_ci if (ret < 0) { 868c2ecf20Sopenharmony_ci wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); 878c2ecf20Sopenharmony_ci goto out; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci gp->tx_bip_fem_manufacturer = 918c2ecf20Sopenharmony_ci gen_parms->general_params.tx_bip_fem_manufacturer; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 948c2ecf20Sopenharmony_ci wl1271_warning("FEM index from FW out of bounds"); 958c2ecf20Sopenharmony_ci ret = -EINVAL; 968c2ecf20Sopenharmony_ci goto out; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* If we are in calibrator based fem auto detect - save fem nr */ 1008c2ecf20Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 1018c2ecf20Sopenharmony_ci wl->fem_manuf = gp->tx_bip_fem_manufacturer; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", 1048c2ecf20Sopenharmony_ci answer == false ? 1058c2ecf20Sopenharmony_ci "manual" : 1068c2ecf20Sopenharmony_ci wl->plt_mode == PLT_FEM_DETECT ? 1078c2ecf20Sopenharmony_ci "calibrator_fem_detect" : 1088c2ecf20Sopenharmony_ci "auto", 1098c2ecf20Sopenharmony_ci gp->tx_bip_fem_manufacturer); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciout: 1128c2ecf20Sopenharmony_ci kfree(gen_parms); 1138c2ecf20Sopenharmony_ci return ret; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciint wl128x_cmd_general_parms(struct wl1271 *wl) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct wl128x_general_parms_cmd *gen_parms; 1198c2ecf20Sopenharmony_ci struct wl128x_ini_general_params *gp = 1208c2ecf20Sopenharmony_ci &((struct wl128x_nvs_file *)wl->nvs)->general_params; 1218c2ecf20Sopenharmony_ci struct wl12xx_priv *priv = wl->priv; 1228c2ecf20Sopenharmony_ci bool answer = false; 1238c2ecf20Sopenharmony_ci int ret; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (!wl->nvs) 1268c2ecf20Sopenharmony_ci return -ENODEV; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 1298c2ecf20Sopenharmony_ci wl1271_warning("FEM index from ini out of bounds"); 1308c2ecf20Sopenharmony_ci return -EINVAL; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); 1348c2ecf20Sopenharmony_ci if (!gen_parms) 1358c2ecf20Sopenharmony_ci return -ENOMEM; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci memcpy(&gen_parms->general_params, gp, sizeof(*gp)); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* If we started in PLT FEM_DETECT mode, force auto detect */ 1428c2ecf20Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 1438c2ecf20Sopenharmony_ci gen_parms->general_params.tx_bip_fem_auto_detect = true; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (gen_parms->general_params.tx_bip_fem_auto_detect) 1468c2ecf20Sopenharmony_ci answer = true; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Replace REF and TCXO CLKs with the ones from platform data */ 1498c2ecf20Sopenharmony_ci gen_parms->general_params.ref_clock = priv->ref_clock; 1508c2ecf20Sopenharmony_ci gen_parms->general_params.tcxo_ref_clock = priv->tcxo_clock; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); 1538c2ecf20Sopenharmony_ci if (ret < 0) { 1548c2ecf20Sopenharmony_ci wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); 1558c2ecf20Sopenharmony_ci goto out; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci gp->tx_bip_fem_manufacturer = 1598c2ecf20Sopenharmony_ci gen_parms->general_params.tx_bip_fem_manufacturer; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 1628c2ecf20Sopenharmony_ci wl1271_warning("FEM index from FW out of bounds"); 1638c2ecf20Sopenharmony_ci ret = -EINVAL; 1648c2ecf20Sopenharmony_ci goto out; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* If we are in calibrator based fem auto detect - save fem nr */ 1688c2ecf20Sopenharmony_ci if (wl->plt_mode == PLT_FEM_DETECT) 1698c2ecf20Sopenharmony_ci wl->fem_manuf = gp->tx_bip_fem_manufacturer; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", 1728c2ecf20Sopenharmony_ci answer == false ? 1738c2ecf20Sopenharmony_ci "manual" : 1748c2ecf20Sopenharmony_ci wl->plt_mode == PLT_FEM_DETECT ? 1758c2ecf20Sopenharmony_ci "calibrator_fem_detect" : 1768c2ecf20Sopenharmony_ci "auto", 1778c2ecf20Sopenharmony_ci gp->tx_bip_fem_manufacturer); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ciout: 1808c2ecf20Sopenharmony_ci kfree(gen_parms); 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciint wl1271_cmd_radio_parms(struct wl1271 *wl) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; 1878c2ecf20Sopenharmony_ci struct wl1271_radio_parms_cmd *radio_parms; 1888c2ecf20Sopenharmony_ci struct wl1271_ini_general_params *gp = &nvs->general_params; 1898c2ecf20Sopenharmony_ci int ret, fem_idx; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (!wl->nvs) 1928c2ecf20Sopenharmony_ci return -ENODEV; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); 1958c2ecf20Sopenharmony_ci if (!radio_parms) 1968c2ecf20Sopenharmony_ci return -ENOMEM; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* 2.4GHz parameters */ 2038c2ecf20Sopenharmony_ci memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, 2048c2ecf20Sopenharmony_ci sizeof(struct wl1271_ini_band_params_2)); 2058c2ecf20Sopenharmony_ci memcpy(&radio_parms->dyn_params_2, 2068c2ecf20Sopenharmony_ci &nvs->dyn_radio_params_2[fem_idx].params, 2078c2ecf20Sopenharmony_ci sizeof(struct wl1271_ini_fem_params_2)); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* 5GHz parameters */ 2108c2ecf20Sopenharmony_ci memcpy(&radio_parms->static_params_5, 2118c2ecf20Sopenharmony_ci &nvs->stat_radio_params_5, 2128c2ecf20Sopenharmony_ci sizeof(struct wl1271_ini_band_params_5)); 2138c2ecf20Sopenharmony_ci memcpy(&radio_parms->dyn_params_5, 2148c2ecf20Sopenharmony_ci &nvs->dyn_radio_params_5[fem_idx].params, 2158c2ecf20Sopenharmony_ci sizeof(struct wl1271_ini_fem_params_5)); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 2188c2ecf20Sopenharmony_ci radio_parms, sizeof(*radio_parms)); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); 2218c2ecf20Sopenharmony_ci if (ret < 0) 2228c2ecf20Sopenharmony_ci wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci kfree(radio_parms); 2258c2ecf20Sopenharmony_ci return ret; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciint wl128x_cmd_radio_parms(struct wl1271 *wl) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; 2318c2ecf20Sopenharmony_ci struct wl128x_radio_parms_cmd *radio_parms; 2328c2ecf20Sopenharmony_ci struct wl128x_ini_general_params *gp = &nvs->general_params; 2338c2ecf20Sopenharmony_ci int ret, fem_idx; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!wl->nvs) 2368c2ecf20Sopenharmony_ci return -ENODEV; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); 2398c2ecf20Sopenharmony_ci if (!radio_parms) 2408c2ecf20Sopenharmony_ci return -ENOMEM; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2.4GHz parameters */ 2478c2ecf20Sopenharmony_ci memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, 2488c2ecf20Sopenharmony_ci sizeof(struct wl128x_ini_band_params_2)); 2498c2ecf20Sopenharmony_ci memcpy(&radio_parms->dyn_params_2, 2508c2ecf20Sopenharmony_ci &nvs->dyn_radio_params_2[fem_idx].params, 2518c2ecf20Sopenharmony_ci sizeof(struct wl128x_ini_fem_params_2)); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* 5GHz parameters */ 2548c2ecf20Sopenharmony_ci memcpy(&radio_parms->static_params_5, 2558c2ecf20Sopenharmony_ci &nvs->stat_radio_params_5, 2568c2ecf20Sopenharmony_ci sizeof(struct wl128x_ini_band_params_5)); 2578c2ecf20Sopenharmony_ci memcpy(&radio_parms->dyn_params_5, 2588c2ecf20Sopenharmony_ci &nvs->dyn_radio_params_5[fem_idx].params, 2598c2ecf20Sopenharmony_ci sizeof(struct wl128x_ini_fem_params_5)); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 2648c2ecf20Sopenharmony_ci radio_parms, sizeof(*radio_parms)); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); 2678c2ecf20Sopenharmony_ci if (ret < 0) 2688c2ecf20Sopenharmony_ci wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci kfree(radio_parms); 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ciint wl12xx_cmd_channel_switch(struct wl1271 *wl, 2758c2ecf20Sopenharmony_ci struct wl12xx_vif *wlvif, 2768c2ecf20Sopenharmony_ci struct ieee80211_channel_switch *ch_switch) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct wl12xx_cmd_channel_switch *cmd; 2798c2ecf20Sopenharmony_ci int ret; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci wl1271_debug(DEBUG_ACX, "cmd channel switch"); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2848c2ecf20Sopenharmony_ci if (!cmd) { 2858c2ecf20Sopenharmony_ci ret = -ENOMEM; 2868c2ecf20Sopenharmony_ci goto out; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci cmd->role_id = wlvif->role_id; 2908c2ecf20Sopenharmony_ci cmd->channel = ch_switch->chandef.chan->hw_value; 2918c2ecf20Sopenharmony_ci cmd->switch_time = ch_switch->count; 2928c2ecf20Sopenharmony_ci cmd->stop_tx = ch_switch->block_tx; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* FIXME: control from mac80211 in the future */ 2958c2ecf20Sopenharmony_ci /* Enable TX on the target channel */ 2968c2ecf20Sopenharmony_ci cmd->post_switch_tx_disable = 0; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); 2998c2ecf20Sopenharmony_ci if (ret < 0) { 3008c2ecf20Sopenharmony_ci wl1271_error("failed to send channel switch command"); 3018c2ecf20Sopenharmony_ci goto out_free; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciout_free: 3058c2ecf20Sopenharmony_ci kfree(cmd); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ciout: 3088c2ecf20Sopenharmony_ci return ret; 3098c2ecf20Sopenharmony_ci} 310