Branch data Line data Source code
1 : : // SPDX-License-Identifier: ISC
2 : : /*
3 : : * Copyright (c) 2005-2011 Atheros Communications Inc.
4 : : * Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc.
5 : : */
6 : :
7 : : #include "bmi.h"
8 : : #include "hif.h"
9 : : #include "debug.h"
10 : : #include "htc.h"
11 : : #include "hw.h"
12 : :
13 : 0 : void ath10k_bmi_start(struct ath10k *ar)
14 : : {
15 : 0 : int ret;
16 : :
17 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
18 : :
19 : 0 : ar->bmi.done_sent = false;
20 : :
21 : : /* Enable hardware clock to speed up firmware download */
22 [ # # ]: 0 : if (ar->hw_params.hw_ops->enable_pll_clk) {
23 : 0 : ret = ar->hw_params.hw_ops->enable_pll_clk(ar);
24 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi enable pll ret %d\n", ret);
25 : : }
26 : 0 : }
27 : :
28 : 0 : int ath10k_bmi_done(struct ath10k *ar)
29 : : {
30 : 0 : struct bmi_cmd cmd;
31 : 0 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
32 : 0 : int ret;
33 : :
34 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
35 : :
36 [ # # ]: 0 : if (ar->bmi.done_sent) {
37 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
38 : 0 : return 0;
39 : : }
40 : :
41 : 0 : ar->bmi.done_sent = true;
42 : 0 : cmd.id = __cpu_to_le32(BMI_DONE);
43 : :
44 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
45 [ # # ]: 0 : if (ret) {
46 : 0 : ath10k_warn(ar, "unable to write to the device: %d\n", ret);
47 : 0 : return ret;
48 : : }
49 : :
50 : : return 0;
51 : : }
52 : :
53 : 7 : int ath10k_bmi_get_target_info(struct ath10k *ar,
54 : : struct bmi_target_info *target_info)
55 : : {
56 : 7 : struct bmi_cmd cmd;
57 : 7 : union bmi_resp resp;
58 : 7 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
59 : 7 : u32 resplen = sizeof(resp.get_target_info);
60 : 7 : int ret;
61 : :
62 [ + - ]: 7 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
63 : :
64 [ - + ]: 7 : if (ar->bmi.done_sent) {
65 : 0 : ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
66 : 0 : return -EBUSY;
67 : : }
68 : :
69 : 7 : cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
70 : :
71 : 7 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
72 [ - + ]: 7 : if (ret) {
73 : 0 : ath10k_warn(ar, "unable to get target info from device\n");
74 : 0 : return ret;
75 : : }
76 : :
77 [ - + ]: 7 : if (resplen < sizeof(resp.get_target_info)) {
78 : 0 : ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
79 : : resplen);
80 : 0 : return -EIO;
81 : : }
82 : :
83 : 7 : target_info->version = __le32_to_cpu(resp.get_target_info.version);
84 : 7 : target_info->type = __le32_to_cpu(resp.get_target_info.type);
85 : :
86 : 7 : return 0;
87 : : }
88 : :
89 : : #define TARGET_VERSION_SENTINAL 0xffffffffu
90 : :
91 : 0 : int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
92 : : struct bmi_target_info *target_info)
93 : : {
94 : 0 : struct bmi_cmd cmd;
95 : 0 : union bmi_resp resp;
96 : 0 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
97 : 0 : u32 resplen, ver_len;
98 : 0 : __le32 tmp;
99 : 0 : int ret;
100 : :
101 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info SDIO\n");
102 : :
103 [ # # ]: 0 : if (ar->bmi.done_sent) {
104 : 0 : ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
105 : 0 : return -EBUSY;
106 : : }
107 : :
108 : 0 : cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
109 : :
110 : : /* Step 1: Read 4 bytes of the target info and check if it is
111 : : * the special sentinal version word or the first word in the
112 : : * version response.
113 : : */
114 : 0 : resplen = sizeof(u32);
115 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &tmp, &resplen);
116 [ # # ]: 0 : if (ret) {
117 : 0 : ath10k_warn(ar, "unable to read from device\n");
118 : 0 : return ret;
119 : : }
120 : :
121 : : /* Some SDIO boards have a special sentinal byte before the real
122 : : * version response.
123 : : */
124 [ # # ]: 0 : if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) {
125 : : /* Step 1b: Read the version length */
126 : 0 : resplen = sizeof(u32);
127 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, &tmp,
128 : : &resplen);
129 [ # # ]: 0 : if (ret) {
130 : 0 : ath10k_warn(ar, "unable to read from device\n");
131 : 0 : return ret;
132 : : }
133 : : }
134 : :
135 : 0 : ver_len = __le32_to_cpu(tmp);
136 : :
137 : : /* Step 2: Check the target info length */
138 [ # # ]: 0 : if (ver_len != sizeof(resp.get_target_info)) {
139 : 0 : ath10k_warn(ar, "Unexpected target info len: %u. Expected: %zu\n",
140 : : ver_len, sizeof(resp.get_target_info));
141 : 0 : return -EINVAL;
142 : : }
143 : :
144 : : /* Step 3: Read the rest of the version response */
145 : 0 : resplen = sizeof(resp.get_target_info) - sizeof(u32);
146 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0,
147 : : &resp.get_target_info.version,
148 : : &resplen);
149 [ # # ]: 0 : if (ret) {
150 : 0 : ath10k_warn(ar, "unable to read from device\n");
151 : 0 : return ret;
152 : : }
153 : :
154 : 0 : target_info->version = __le32_to_cpu(resp.get_target_info.version);
155 : 0 : target_info->type = __le32_to_cpu(resp.get_target_info.type);
156 : :
157 : 0 : return 0;
158 : : }
159 : :
160 : 0 : int ath10k_bmi_read_memory(struct ath10k *ar,
161 : : u32 address, void *buffer, u32 length)
162 : : {
163 : 0 : struct bmi_cmd cmd;
164 : 0 : union bmi_resp resp;
165 : 0 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_mem);
166 : 0 : u32 rxlen;
167 : 0 : int ret;
168 : :
169 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
170 : : address, length);
171 : :
172 [ # # ]: 0 : if (ar->bmi.done_sent) {
173 : 0 : ath10k_warn(ar, "command disallowed\n");
174 : 0 : return -EBUSY;
175 : : }
176 : :
177 [ # # ]: 0 : while (length) {
178 : 0 : rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
179 : :
180 : 0 : cmd.id = __cpu_to_le32(BMI_READ_MEMORY);
181 : 0 : cmd.read_mem.addr = __cpu_to_le32(address);
182 : 0 : cmd.read_mem.len = __cpu_to_le32(rxlen);
183 : :
184 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
185 : : &resp, &rxlen);
186 [ # # ]: 0 : if (ret) {
187 : 0 : ath10k_warn(ar, "unable to read from the device (%d)\n",
188 : : ret);
189 : 0 : return ret;
190 : : }
191 : :
192 : 0 : memcpy(buffer, resp.read_mem.payload, rxlen);
193 : 0 : address += rxlen;
194 : 0 : buffer += rxlen;
195 : 0 : length -= rxlen;
196 : : }
197 : :
198 : : return 0;
199 : : }
200 : :
201 : 0 : int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
202 : : {
203 : 0 : struct bmi_cmd cmd;
204 : 0 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.write_soc_reg);
205 : 0 : int ret;
206 : :
207 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI,
208 : : "bmi write soc register 0x%08x val 0x%08x\n",
209 : : address, reg_val);
210 : :
211 [ # # ]: 0 : if (ar->bmi.done_sent) {
212 : 0 : ath10k_warn(ar, "bmi write soc register command in progress\n");
213 : 0 : return -EBUSY;
214 : : }
215 : :
216 : 0 : cmd.id = __cpu_to_le32(BMI_WRITE_SOC_REGISTER);
217 : 0 : cmd.write_soc_reg.addr = __cpu_to_le32(address);
218 : 0 : cmd.write_soc_reg.value = __cpu_to_le32(reg_val);
219 : :
220 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
221 [ # # ]: 0 : if (ret) {
222 : 0 : ath10k_warn(ar, "Unable to write soc register to device: %d\n",
223 : : ret);
224 : 0 : return ret;
225 : : }
226 : :
227 : : return 0;
228 : : }
229 : :
230 : 0 : int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val)
231 : : {
232 : 0 : struct bmi_cmd cmd;
233 : 0 : union bmi_resp resp;
234 : 0 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_soc_reg);
235 : 0 : u32 resplen = sizeof(resp.read_soc_reg);
236 : 0 : int ret;
237 : :
238 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register 0x%08x\n",
239 : : address);
240 : :
241 [ # # ]: 0 : if (ar->bmi.done_sent) {
242 : 0 : ath10k_warn(ar, "bmi read soc register command in progress\n");
243 : 0 : return -EBUSY;
244 : : }
245 : :
246 : 0 : cmd.id = __cpu_to_le32(BMI_READ_SOC_REGISTER);
247 : 0 : cmd.read_soc_reg.addr = __cpu_to_le32(address);
248 : :
249 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
250 [ # # ]: 0 : if (ret) {
251 : 0 : ath10k_warn(ar, "Unable to read soc register from device: %d\n",
252 : : ret);
253 : 0 : return ret;
254 : : }
255 : :
256 : 0 : *reg_val = __le32_to_cpu(resp.read_soc_reg.value);
257 : :
258 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register value 0x%08x\n",
259 : : *reg_val);
260 : :
261 : : return 0;
262 : : }
263 : :
264 : 0 : int ath10k_bmi_write_memory(struct ath10k *ar,
265 : : u32 address, const void *buffer, u32 length)
266 : : {
267 : 0 : struct bmi_cmd cmd;
268 : 0 : u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.write_mem);
269 : 0 : u32 txlen;
270 : 0 : int ret;
271 : :
272 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
273 : : address, length);
274 : :
275 [ # # ]: 0 : if (ar->bmi.done_sent) {
276 : 0 : ath10k_warn(ar, "command disallowed\n");
277 : 0 : return -EBUSY;
278 : : }
279 : :
280 [ # # ]: 0 : while (length) {
281 : 0 : txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
282 : :
283 : : /* copy before roundup to avoid reading beyond buffer*/
284 : 0 : memcpy(cmd.write_mem.payload, buffer, txlen);
285 : 0 : txlen = roundup(txlen, 4);
286 : :
287 : 0 : cmd.id = __cpu_to_le32(BMI_WRITE_MEMORY);
288 : 0 : cmd.write_mem.addr = __cpu_to_le32(address);
289 : 0 : cmd.write_mem.len = __cpu_to_le32(txlen);
290 : :
291 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
292 : : NULL, NULL);
293 [ # # ]: 0 : if (ret) {
294 : 0 : ath10k_warn(ar, "unable to write to the device (%d)\n",
295 : : ret);
296 : 0 : return ret;
297 : : }
298 : :
299 : : /* fixup roundup() so `length` zeroes out for last chunk */
300 : 0 : txlen = min(txlen, length);
301 : :
302 : 0 : address += txlen;
303 : 0 : buffer += txlen;
304 : 0 : length -= txlen;
305 : : }
306 : :
307 : : return 0;
308 : : }
309 : :
310 : 0 : int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
311 : : {
312 : 0 : struct bmi_cmd cmd;
313 : 0 : union bmi_resp resp;
314 : 0 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.execute);
315 : 0 : u32 resplen = sizeof(resp.execute);
316 : 0 : int ret;
317 : :
318 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
319 : : address, param);
320 : :
321 [ # # ]: 0 : if (ar->bmi.done_sent) {
322 : 0 : ath10k_warn(ar, "command disallowed\n");
323 : 0 : return -EBUSY;
324 : : }
325 : :
326 : 0 : cmd.id = __cpu_to_le32(BMI_EXECUTE);
327 : 0 : cmd.execute.addr = __cpu_to_le32(address);
328 : 0 : cmd.execute.param = __cpu_to_le32(param);
329 : :
330 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
331 [ # # ]: 0 : if (ret) {
332 : 0 : ath10k_warn(ar, "unable to read from the device\n");
333 : 0 : return ret;
334 : : }
335 : :
336 [ # # ]: 0 : if (resplen < sizeof(resp.execute)) {
337 : 0 : ath10k_warn(ar, "invalid execute response length (%d)\n",
338 : : resplen);
339 : 0 : return -EIO;
340 : : }
341 : :
342 : 0 : *result = __le32_to_cpu(resp.execute.result);
343 : :
344 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
345 : :
346 : : return 0;
347 : : }
348 : :
349 : 0 : static int ath10k_bmi_lz_data_large(struct ath10k *ar, const void *buffer, u32 length)
350 : : {
351 : 0 : struct bmi_cmd *cmd;
352 : 0 : u32 hdrlen = sizeof(cmd->id) + sizeof(cmd->lz_data);
353 : 0 : u32 txlen;
354 : 0 : int ret;
355 : 0 : size_t buf_len;
356 : :
357 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "large bmi lz data buffer 0x%pK length %d\n",
358 : : buffer, length);
359 : :
360 [ # # ]: 0 : if (ar->bmi.done_sent) {
361 : 0 : ath10k_warn(ar, "command disallowed\n");
362 : 0 : return -EBUSY;
363 : : }
364 : :
365 : 0 : buf_len = sizeof(*cmd) + BMI_MAX_LARGE_DATA_SIZE - BMI_MAX_DATA_SIZE;
366 : 0 : cmd = kzalloc(buf_len, GFP_KERNEL);
367 [ # # ]: 0 : if (!cmd)
368 : : return -ENOMEM;
369 : :
370 [ # # ]: 0 : while (length) {
371 : 0 : txlen = min(length, BMI_MAX_LARGE_DATA_SIZE - hdrlen);
372 : :
373 [ # # ]: 0 : WARN_ON_ONCE(txlen & 3);
374 : :
375 : 0 : cmd->id = __cpu_to_le32(BMI_LZ_DATA);
376 : 0 : cmd->lz_data.len = __cpu_to_le32(txlen);
377 : 0 : memcpy(cmd->lz_data.payload, buffer, txlen);
378 : :
379 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, cmd, hdrlen + txlen,
380 : : NULL, NULL);
381 [ # # ]: 0 : if (ret) {
382 : 0 : ath10k_warn(ar, "unable to write to the device\n");
383 : 0 : return ret;
384 : : }
385 : :
386 : 0 : buffer += txlen;
387 : 0 : length -= txlen;
388 : : }
389 : :
390 : 0 : kfree(cmd);
391 : :
392 : 0 : return 0;
393 : : }
394 : :
395 : 0 : int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
396 : : {
397 : 0 : struct bmi_cmd cmd;
398 : 0 : u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.lz_data);
399 : 0 : u32 txlen;
400 : 0 : int ret;
401 : :
402 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%pK length %d\n",
403 : : buffer, length);
404 : :
405 [ # # ]: 0 : if (ar->bmi.done_sent) {
406 : 0 : ath10k_warn(ar, "command disallowed\n");
407 : 0 : return -EBUSY;
408 : : }
409 : :
410 [ # # ]: 0 : while (length) {
411 : 0 : txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
412 : :
413 [ # # ]: 0 : WARN_ON_ONCE(txlen & 3);
414 : :
415 : 0 : cmd.id = __cpu_to_le32(BMI_LZ_DATA);
416 : 0 : cmd.lz_data.len = __cpu_to_le32(txlen);
417 : 0 : memcpy(cmd.lz_data.payload, buffer, txlen);
418 : :
419 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
420 : : NULL, NULL);
421 [ # # ]: 0 : if (ret) {
422 : 0 : ath10k_warn(ar, "unable to write to the device\n");
423 : 0 : return ret;
424 : : }
425 : :
426 : 0 : buffer += txlen;
427 : 0 : length -= txlen;
428 : : }
429 : :
430 : : return 0;
431 : : }
432 : :
433 : 0 : int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
434 : : {
435 : 0 : struct bmi_cmd cmd;
436 : 0 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
437 : 0 : int ret;
438 : :
439 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
440 : : address);
441 : :
442 [ # # ]: 0 : if (ar->bmi.done_sent) {
443 : 0 : ath10k_warn(ar, "command disallowed\n");
444 : 0 : return -EBUSY;
445 : : }
446 : :
447 : 0 : cmd.id = __cpu_to_le32(BMI_LZ_STREAM_START);
448 : 0 : cmd.lz_start.addr = __cpu_to_le32(address);
449 : :
450 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
451 [ # # ]: 0 : if (ret) {
452 : 0 : printk(KERN_INFO "unable to Start LZ Stream to the device\n");
453 : 0 : return ret;
454 : : }
455 : :
456 : : return 0;
457 : : }
458 : :
459 : 0 : int ath10k_bmi_fast_download(struct ath10k *ar,
460 : : u32 address, const void *buffer, u32 length)
461 : : {
462 : 0 : u8 trailer[4] = {};
463 : 0 : u32 head_len = rounddown(length, 4);
464 : 0 : u32 trailer_len = length - head_len;
465 : 0 : int ret;
466 : 0 : printk(KERN_INFO
467 : : "bmi fast download address 0x%x buffer 0x%pK length %d\n",
468 : : address, buffer, length);
469 : :
470 [ # # ]: 0 : ath10k_dbg(ar, ATH10K_DBG_BMI,
471 : : "bmi fast download address 0x%x buffer 0x%pK length %d\n",
472 : : address, buffer, length);
473 : :
474 : 0 : ret = ath10k_bmi_lz_stream_start(ar, address);
475 [ # # ]: 0 : if (ret)
476 : : return ret;
477 : 0 : printk(KERN_INFO "lz_stream_start\n");
478 : :
479 : : /* copy the last word into a zero padded buffer */
480 [ # # ]: 0 : if (trailer_len > 0)
481 : 0 : memcpy(trailer, buffer + head_len, trailer_len);
482 : :
483 [ # # ]: 0 : if (ar->hw_params.bmi_large_size_download)
484 : 0 : ret = ath10k_bmi_lz_data_large(ar, buffer, head_len);
485 : : else
486 : 0 : ret = ath10k_bmi_lz_data(ar, buffer, head_len);
487 : :
488 [ # # ]: 0 : if (ret)
489 : : return ret;
490 : 0 : printk(KERN_INFO "lz_data buf\n");
491 : :
492 [ # # ]: 0 : if (trailer_len > 0)
493 : 0 : ret = ath10k_bmi_lz_data(ar, trailer, 4);
494 : :
495 [ # # ]: 0 : if (ret != 0)
496 : : return ret;
497 : 0 : printk(KERN_INFO "lz_data trail\n");
498 : :
499 : : /*
500 : : * Close compressed stream and open a new (fake) one.
501 : : * This serves mainly to flush Target caches.
502 : : */
503 : 0 : ret = ath10k_bmi_lz_stream_start(ar, 0x00);
504 : :
505 : 0 : return ret;
506 : : }
507 : :
508 : 0 : int ath10k_bmi_set_start(struct ath10k *ar, u32 address)
509 : : {
510 : 0 : struct bmi_cmd cmd;
511 : 0 : u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.set_app_start);
512 : 0 : int ret;
513 : :
514 [ # # ]: 0 : if (ar->bmi.done_sent) {
515 : 0 : ath10k_warn(ar, "bmi set start command disallowed\n");
516 : 0 : return -EBUSY;
517 : : }
518 : :
519 : 0 : cmd.id = __cpu_to_le32(BMI_SET_APP_START);
520 : 0 : cmd.set_app_start.addr = __cpu_to_le32(address);
521 : :
522 : 0 : ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
523 [ # # ]: 0 : if (ret) {
524 : 0 : ath10k_warn(ar, "unable to set start to the device:%d\n", ret);
525 : 0 : return ret;
526 : : }
527 : :
528 : : return 0;
529 : : }
|