cmd.c 8.3 KB

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