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 
wl1271_cmd_ext_radio_parms(struct wl1271 * wl)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 
wl1271_cmd_general_parms(struct wl1271 * wl)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 
wl128x_cmd_general_parms(struct wl1271 * wl)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 
wl1271_cmd_radio_parms(struct wl1271 * wl)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 
wl128x_cmd_radio_parms(struct wl1271 * wl)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 
wl12xx_cmd_channel_switch(struct wl1271 * wl,struct wl12xx_vif * wlvif,struct ieee80211_channel_switch * ch_switch)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