1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * This file is part of wl12xx 4 * 5 * Copyright (C) 2009-2010 Nokia Corporation 6 * Copyright (C) 2011 Texas Instruments Inc. 7 */ 8 9 #include "../wlcore/cmd.h" 10 #include "../wlcore/debug.h" 11 12 #include "wl12xx.h" 13 #include "cmd.h" 14 15 int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) 16 { 17 struct wl1271_ext_radio_parms_cmd *ext_radio_parms; 18 struct wl12xx_priv *priv = wl->priv; 19 struct wl12xx_conf_rf *rf = &priv->conf.rf; 20 int ret; 21 22 if (!wl->nvs) 23 return -ENODEV; 24 25 ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL); 26 if (!ext_radio_parms) 27 return -ENOMEM; 28 29 ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM; 30 31 memcpy(ext_radio_parms->tx_per_channel_power_compensation_2, 32 rf->tx_per_channel_power_compensation_2, 33 CONF_TX_PWR_COMPENSATION_LEN_2); 34 memcpy(ext_radio_parms->tx_per_channel_power_compensation_5, 35 rf->tx_per_channel_power_compensation_5, 36 CONF_TX_PWR_COMPENSATION_LEN_5); 37 38 wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ", 39 ext_radio_parms, sizeof(*ext_radio_parms)); 40 41 ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0); 42 if (ret < 0) 43 wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed"); 44 45 kfree(ext_radio_parms); 46 return ret; 47 } 48 49 int wl1271_cmd_general_parms(struct wl1271 *wl) 50 { 51 struct wl1271_general_parms_cmd *gen_parms; 52 struct wl1271_ini_general_params *gp = 53 &((struct wl1271_nvs_file *)wl->nvs)->general_params; 54 struct wl12xx_priv *priv = wl->priv; 55 bool answer = false; 56 int ret; 57 58 if (!wl->nvs) 59 return -ENODEV; 60 61 if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 62 wl1271_warning("FEM index from INI out of bounds"); 63 return -EINVAL; 64 } 65 66 gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); 67 if (!gen_parms) 68 return -ENOMEM; 69 70 gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 71 72 memcpy(&gen_parms->general_params, gp, sizeof(*gp)); 73 74 /* If we started in PLT FEM_DETECT mode, force auto detect */ 75 if (wl->plt_mode == PLT_FEM_DETECT) 76 gen_parms->general_params.tx_bip_fem_auto_detect = true; 77 78 if (gen_parms->general_params.tx_bip_fem_auto_detect) 79 answer = true; 80 81 /* Override the REF CLK from the NVS with the one from platform data */ 82 gen_parms->general_params.ref_clock = priv->ref_clock; 83 84 ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); 85 if (ret < 0) { 86 wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); 87 goto out; 88 } 89 90 gp->tx_bip_fem_manufacturer = 91 gen_parms->general_params.tx_bip_fem_manufacturer; 92 93 if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 94 wl1271_warning("FEM index from FW out of bounds"); 95 ret = -EINVAL; 96 goto out; 97 } 98 99 /* If we are in calibrator based fem auto detect - save fem nr */ 100 if (wl->plt_mode == PLT_FEM_DETECT) 101 wl->fem_manuf = gp->tx_bip_fem_manufacturer; 102 103 wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", 104 answer == false ? 105 "manual" : 106 wl->plt_mode == PLT_FEM_DETECT ? 107 "calibrator_fem_detect" : 108 "auto", 109 gp->tx_bip_fem_manufacturer); 110 111 out: 112 kfree(gen_parms); 113 return ret; 114 } 115 116 int wl128x_cmd_general_parms(struct wl1271 *wl) 117 { 118 struct wl128x_general_parms_cmd *gen_parms; 119 struct wl128x_ini_general_params *gp = 120 &((struct wl128x_nvs_file *)wl->nvs)->general_params; 121 struct wl12xx_priv *priv = wl->priv; 122 bool answer = false; 123 int ret; 124 125 if (!wl->nvs) 126 return -ENODEV; 127 128 if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 129 wl1271_warning("FEM index from ini out of bounds"); 130 return -EINVAL; 131 } 132 133 gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); 134 if (!gen_parms) 135 return -ENOMEM; 136 137 gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; 138 139 memcpy(&gen_parms->general_params, gp, sizeof(*gp)); 140 141 /* If we started in PLT FEM_DETECT mode, force auto detect */ 142 if (wl->plt_mode == PLT_FEM_DETECT) 143 gen_parms->general_params.tx_bip_fem_auto_detect = true; 144 145 if (gen_parms->general_params.tx_bip_fem_auto_detect) 146 answer = true; 147 148 /* Replace REF and TCXO CLKs with the ones from platform data */ 149 gen_parms->general_params.ref_clock = priv->ref_clock; 150 gen_parms->general_params.tcxo_ref_clock = priv->tcxo_clock; 151 152 ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); 153 if (ret < 0) { 154 wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); 155 goto out; 156 } 157 158 gp->tx_bip_fem_manufacturer = 159 gen_parms->general_params.tx_bip_fem_manufacturer; 160 161 if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { 162 wl1271_warning("FEM index from FW out of bounds"); 163 ret = -EINVAL; 164 goto out; 165 } 166 167 /* If we are in calibrator based fem auto detect - save fem nr */ 168 if (wl->plt_mode == PLT_FEM_DETECT) 169 wl->fem_manuf = gp->tx_bip_fem_manufacturer; 170 171 wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", 172 answer == false ? 173 "manual" : 174 wl->plt_mode == PLT_FEM_DETECT ? 175 "calibrator_fem_detect" : 176 "auto", 177 gp->tx_bip_fem_manufacturer); 178 179 out: 180 kfree(gen_parms); 181 return ret; 182 } 183 184 int wl1271_cmd_radio_parms(struct wl1271 *wl) 185 { 186 struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; 187 struct wl1271_radio_parms_cmd *radio_parms; 188 struct wl1271_ini_general_params *gp = &nvs->general_params; 189 int ret, fem_idx; 190 191 if (!wl->nvs) 192 return -ENODEV; 193 194 radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); 195 if (!radio_parms) 196 return -ENOMEM; 197 198 radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 199 200 fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); 201 202 /* 2.4GHz parameters */ 203 memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, 204 sizeof(struct wl1271_ini_band_params_2)); 205 memcpy(&radio_parms->dyn_params_2, 206 &nvs->dyn_radio_params_2[fem_idx].params, 207 sizeof(struct wl1271_ini_fem_params_2)); 208 209 /* 5GHz parameters */ 210 memcpy(&radio_parms->static_params_5, 211 &nvs->stat_radio_params_5, 212 sizeof(struct wl1271_ini_band_params_5)); 213 memcpy(&radio_parms->dyn_params_5, 214 &nvs->dyn_radio_params_5[fem_idx].params, 215 sizeof(struct wl1271_ini_fem_params_5)); 216 217 wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 218 radio_parms, sizeof(*radio_parms)); 219 220 ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); 221 if (ret < 0) 222 wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); 223 224 kfree(radio_parms); 225 return ret; 226 } 227 228 int wl128x_cmd_radio_parms(struct wl1271 *wl) 229 { 230 struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; 231 struct wl128x_radio_parms_cmd *radio_parms; 232 struct wl128x_ini_general_params *gp = &nvs->general_params; 233 int ret, fem_idx; 234 235 if (!wl->nvs) 236 return -ENODEV; 237 238 radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); 239 if (!radio_parms) 240 return -ENOMEM; 241 242 radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; 243 244 fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); 245 246 /* 2.4GHz parameters */ 247 memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, 248 sizeof(struct wl128x_ini_band_params_2)); 249 memcpy(&radio_parms->dyn_params_2, 250 &nvs->dyn_radio_params_2[fem_idx].params, 251 sizeof(struct wl128x_ini_fem_params_2)); 252 253 /* 5GHz parameters */ 254 memcpy(&radio_parms->static_params_5, 255 &nvs->stat_radio_params_5, 256 sizeof(struct wl128x_ini_band_params_5)); 257 memcpy(&radio_parms->dyn_params_5, 258 &nvs->dyn_radio_params_5[fem_idx].params, 259 sizeof(struct wl128x_ini_fem_params_5)); 260 261 radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; 262 263 wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", 264 radio_parms, sizeof(*radio_parms)); 265 266 ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); 267 if (ret < 0) 268 wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); 269 270 kfree(radio_parms); 271 return ret; 272 } 273 274 int wl12xx_cmd_channel_switch(struct wl1271 *wl, 275 struct wl12xx_vif *wlvif, 276 struct ieee80211_channel_switch *ch_switch) 277 { 278 struct wl12xx_cmd_channel_switch *cmd; 279 int ret; 280 281 wl1271_debug(DEBUG_ACX, "cmd channel switch"); 282 283 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 284 if (!cmd) { 285 ret = -ENOMEM; 286 goto out; 287 } 288 289 cmd->role_id = wlvif->role_id; 290 cmd->channel = ch_switch->chandef.chan->hw_value; 291 cmd->switch_time = ch_switch->count; 292 cmd->stop_tx = ch_switch->block_tx; 293 294 /* FIXME: control from mac80211 in the future */ 295 /* Enable TX on the target channel */ 296 cmd->post_switch_tx_disable = 0; 297 298 ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); 299 if (ret < 0) { 300 wl1271_error("failed to send channel switch command"); 301 goto out_free; 302 } 303 304 out_free: 305 kfree(cmd); 306 307 out: 308 return ret; 309 } 310