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(size: 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, buf: ext_radio_parms, buf_len: sizeof(*ext_radio_parms), answer: 0); |
42 | if (ret < 0) |
43 | wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed" ); |
44 | |
45 | kfree(objp: 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(size: 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, buf: gen_parms, buf_len: 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(objp: 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(size: 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, buf: gen_parms, buf_len: 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(objp: 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(size: 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, buf: radio_parms, buf_len: sizeof(*radio_parms), answer: 0); |
221 | if (ret < 0) |
222 | wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed" ); |
223 | |
224 | kfree(objp: 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(size: 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, buf: radio_parms, buf_len: sizeof(*radio_parms), answer: 0); |
267 | if (ret < 0) |
268 | wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed" ); |
269 | |
270 | kfree(objp: 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(size: 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, id: CMD_CHANNEL_SWITCH, buf: cmd, len: sizeof(*cmd), res_len: 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(objp: cmd); |
306 | |
307 | out: |
308 | return ret; |
309 | } |
310 | |