blob: cd8ce45bcf2691376a9e9d53c4e52bc4e0786d87 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27#include "i_bmi.h"
28/* This need to defined in firmware interface files.
29 * Defining here to address compilation issues.
30 * Will be deleted once firmware interface files for
31 * target are merged
32 */
33#define BMI_LOAD_IMAGE 18
34
35CDF_STATUS
36bmi_no_command(struct ol_softc *scn)
37{
38 uint32_t cid;
39 int status;
40 uint32_t length;
41 uint8_t ret = 0;
42 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
43 uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff;
44
45 if (scn->bmi_done) {
46 BMI_ERR("Command disallowed: BMI DONE ALREADY");
47 return CDF_STATUS_E_PERM;
48 }
49
50 if (!bmi_cmd_buff || !bmi_rsp_buff) {
51 BMI_ERR("No Memory Allocated for BMI CMD/RSP Buffer");
52 return CDF_STATUS_NOT_INITIALIZED;
53 }
54 cid = BMI_NO_COMMAND;
55
56 cdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid));
57 length = sizeof(ret);
58
59 status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, sizeof(cid),
60 bmi_rsp_buff, &length, BMI_EXCHANGE_TIMEOUT_MS);
61
62 if (status) {
63 BMI_ERR("Failed to write bmi no command status:%d", status);
64 return CDF_STATUS_E_FAILURE;
65 }
66
67 cdf_mem_copy(&ret, bmi_rsp_buff, length);
68 if (ret != 0) {
69 BMI_ERR("bmi no command response error ret 0x%x", ret);
70 return CDF_STATUS_E_FAILURE;
71 }
72 return CDF_STATUS_SUCCESS;
73}
74
75CDF_STATUS
76bmi_done_local(struct ol_softc *scn)
77{
78 uint32_t cid;
79 int status;
80 uint32_t length;
81 uint8_t ret = 0;
82 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
83 uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff;
84
85 if (scn->bmi_done) {
86 BMI_ERR("Command disallowed");
87 return CDF_STATUS_E_PERM;
88 }
89
90 if (!bmi_cmd_buff || !bmi_rsp_buff) {
91 BMI_ERR("No Memory Allocated for BMI CMD/RSP Buffer");
92 return CDF_STATUS_NOT_INITIALIZED;
93 }
94 cid = BMI_DONE;
95
96 cdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid));
97 length = sizeof(ret);
98
99 status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, sizeof(cid),
100 bmi_rsp_buff, &length, BMI_EXCHANGE_TIMEOUT_MS);
101
102 if (status) {
103 BMI_ERR("Failed to close BMI on target status:%d", status);
104 return CDF_STATUS_E_FAILURE;
105 }
106 cdf_mem_copy(&ret, bmi_rsp_buff, length);
107
108 if (ret != 0) {
109 BMI_ERR("BMI DONE response failed:%d", ret);
110 return CDF_STATUS_E_FAILURE;
111 }
112
113 if (scn->bmi_cmd_buff) {
114 cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ,
115 scn->bmi_cmd_buff, scn->bmi_cmd_da, 0);
116 scn->bmi_cmd_buff = NULL;
117 scn->bmi_cmd_da = 0;
118 }
119
120 if (scn->bmi_rsp_buff) {
121 cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ,
122 scn->bmi_rsp_buff, scn->bmi_rsp_da, 0);
123 scn->bmi_rsp_buff = NULL;
124 scn->bmi_rsp_da = 0;
125 }
126
127 return CDF_STATUS_SUCCESS;
128}
129
130CDF_STATUS
131bmi_write_memory(uint32_t address,
132 uint8_t *buffer,
133 uint32_t length,
134 struct ol_softc *scn)
135{
136 uint32_t cid;
137 int status;
138 uint32_t rsp_len;
139 uint8_t ret = 0;
140 uint32_t offset;
141 uint32_t remaining, txlen;
142 const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length);
143 uint8_t aligned_buffer[BMI_DATASZ_MAX];
144 uint8_t *src;
145 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
146 uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff;
147
148 if (scn->bmi_done) {
149 BMI_ERR("Command disallowed");
150 return CDF_STATUS_E_PERM;
151 }
152
153 if (!bmi_cmd_buff || !bmi_rsp_buff) {
154 BMI_ERR("BMI Initialization is not happened");
155 return CDF_STATUS_NOT_INITIALIZED;
156 }
157
158 bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
159 cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header);
160
161 cid = BMI_WRITE_MEMORY;
162 rsp_len = sizeof(ret);
163
164 remaining = length;
165 while (remaining) {
166 src = &buffer[length - remaining];
167 if (remaining < (BMI_DATASZ_MAX - header)) {
168 if (remaining & 3) {
169 /* align it with 4 bytes */
170 remaining = remaining + (4 - (remaining & 3));
171 memcpy(aligned_buffer, src, remaining);
172 src = aligned_buffer;
173 }
174 txlen = remaining;
175 } else {
176 txlen = (BMI_DATASZ_MAX - header);
177 }
178 offset = 0;
179 cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
180 offset += sizeof(cid);
181 cdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
182 sizeof(address));
183 offset += sizeof(address);
184 cdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
185 offset += sizeof(txlen);
186 cdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen);
187 offset += txlen;
188 status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset,
189 bmi_rsp_buff, &rsp_len, BMI_EXCHANGE_TIMEOUT_MS);
190 if (status) {
191 BMI_ERR("BMI Write Memory Failed status:%d", status);
192 return CDF_STATUS_E_FAILURE;
193 }
194 cdf_mem_copy(&ret, bmi_rsp_buff, rsp_len);
195 if (ret != 0) {
196 BMI_ERR("BMI Write memory response fail: %x", ret);
197 return CDF_STATUS_E_FAILURE;
198 }
199 remaining -= txlen; address += txlen;
200 }
201
202 return CDF_STATUS_SUCCESS;
203}
204
205CDF_STATUS
206bmi_read_memory(uint32_t address, uint8_t *buffer,
207 uint32_t length, struct ol_softc *scn)
208{
209 uint32_t cid;
210 int status;
211 uint8_t ret = 0;
212 uint32_t offset;
213 uint32_t remaining, rxlen, rsp_len, total_len;
214 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
215 /* note we reuse the same buffer to receive on */
216 uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff;
217 uint32_t size = sizeof(cid) + sizeof(address) + sizeof(length);
218
219 if (scn->bmi_done) {
220 BMI_ERR("Command disallowed");
221 return CDF_STATUS_E_PERM;
222 }
223 if (!bmi_cmd_buff || !bmi_rsp_buff) {
224 BMI_ERR("BMI Initialization is not done");
225 return CDF_STATUS_NOT_INITIALIZED;
226 }
227
228 bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + size));
229 cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + size);
230 cdf_mem_set(bmi_rsp_buff, 0, BMI_DATASZ_MAX + size);
231
232 cid = BMI_READ_MEMORY;
233 rsp_len = sizeof(ret);
234 remaining = length;
235
236 while (remaining) {
237 rxlen = (remaining < BMI_DATASZ_MAX - rsp_len) ? remaining :
238 (BMI_DATASZ_MAX - rsp_len);
239 offset = 0;
240 cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
241 offset += sizeof(cid);
242 cdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
243 sizeof(address));
244 offset += sizeof(address);
245 cdf_mem_copy(&(bmi_cmd_buff[offset]), &rxlen, sizeof(rxlen));
246 offset += sizeof(length);
247
248 total_len = rxlen + rsp_len;
249
250 status = hif_exchange_bmi_msg(scn,
251 bmi_cmd_buff,
252 offset,
253 bmi_rsp_buff,
254 &total_len,
255 BMI_EXCHANGE_TIMEOUT_MS);
256
257 if (status) {
258 BMI_ERR("BMI Read memory failed status:%d", status);
259 return CDF_STATUS_E_FAILURE;
260 }
261
262 cdf_mem_copy(&ret, bmi_rsp_buff, rsp_len);
263
264 if (ret != 0) {
265 BMI_ERR("bmi read memory response fail %x", ret);
266 return CDF_STATUS_E_FAILURE;
267 }
268
269 cdf_mem_copy(&buffer[length - remaining],
270 (uint8_t *)bmi_rsp_buff + rsp_len, rxlen);
271 remaining -= rxlen; address += rxlen;
272 }
273
274 return CDF_STATUS_SUCCESS;
275}
276
277CDF_STATUS
278bmi_execute(uint32_t address, uint32_t *param,
279 struct ol_softc *scn)
280{
281 uint32_t cid;
282 int status;
283 uint32_t length;
284 uint8_t ret = 0;
285 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
286 uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff;
287
288 if (scn->bmi_done) {
289 BMI_ERR("Command disallowed");
290 return CDF_STATUS_E_PERM;
291 }
292
293 if (!bmi_cmd_buff || !bmi_rsp_buff) {
294 BMI_ERR("No Memory Allocated for bmi buffers");
295 return CDF_STATUS_NOT_INITIALIZED;
296 }
297
298 cid = BMI_EXECUTE;
299
300 cdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid));
301 length = sizeof(ret);
302
303 status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, sizeof(cid),
304 bmi_rsp_buff, &length, BMI_EXCHANGE_TIMEOUT_MS);
305
306 if (status) {
307 BMI_ERR("Failed to do BMI_EXECUTE status:%d", status);
308 return CDF_STATUS_E_FAILURE;
309 }
310
311 cdf_mem_copy(&ret, bmi_rsp_buff, length);
312
313 if (ret != 0) {
314 BMI_ERR("%s: ret 0x%x", __func__, ret);
315 return CDF_STATUS_E_FAILURE;
316 }
317 return CDF_STATUS_SUCCESS;
318}
319
320static CDF_STATUS
321bmi_load_image(dma_addr_t address,
322 uint32_t size, struct ol_softc *scn)
323{
324 uint32_t cid;
325 CDF_STATUS status;
326 uint32_t offset;
327 uint32_t length;
328 uint8_t ret = 0;
329 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
330 uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff;
331 uint32_t addr_h, addr_l;
332
333 if (scn->bmi_done) {
334 BMI_ERR("Command disallowed");
335 return CDF_STATUS_E_PERM;
336 }
337
338 if (!bmi_cmd_buff || !bmi_rsp_buff) {
339 BMI_ERR("No Memory Allocated for BMI CMD/RSP Buffer");
340 return CDF_STATUS_NOT_INITIALIZED;
341 }
342
343 bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
344 cdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address));
345
346
347 BMI_DBG("%s: Enter device: 0x%p, size %d", __func__, scn, size);
348
349 cid = BMI_LOAD_IMAGE;
350
351 offset = 0;
352 cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
353 offset += sizeof(cid);
354 addr_l = address & 0xffffffff;
355 addr_h = 0x00;
356 cdf_mem_copy(&(bmi_cmd_buff[offset]), &addr_l, sizeof(addr_l));
357 offset += sizeof(addr_l);
358 cdf_mem_copy(&(bmi_cmd_buff[offset]), &addr_h, sizeof(addr_h));
359 offset += sizeof(addr_h);
360 cdf_mem_copy(&(bmi_cmd_buff[offset]), &size, sizeof(size));
361 offset += sizeof(size);
362 length = sizeof(ret);
363
364 status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset,
365 bmi_rsp_buff, &length, BMI_EXCHANGE_TIMEOUT_MS);
366
367 if (status) {
368 BMI_ERR("BMI Load Image Failed; status:%d", status);
369 return CDF_STATUS_E_FAILURE;
370 }
371
372 cdf_mem_copy(&ret, bmi_rsp_buff, length);
373 if (ret != 0) {
374 BMI_ERR("%s: ret 0x%x", __func__, ret);
375 return CDF_STATUS_E_FAILURE;
376 }
377 return CDF_STATUS_SUCCESS;
378}
379
380static CDF_STATUS bmi_enable(struct ol_softc *scn)
381{
382 struct bmi_target_info targ_info;
383 struct image_desc_info image_desc_info;
384 CDF_STATUS status;
385
386 if (!scn) {
387 BMI_ERR("Invalid scn context");
388 bmi_assert(0);
389 return CDF_STATUS_NOT_INITIALIZED;
390 }
391
392 if (scn->bmi_cmd_buff == NULL || scn->bmi_rsp_buff == NULL) {
393 BMI_ERR("bmi_open failed!");
394 return CDF_STATUS_NOT_INITIALIZED;
395 }
396
397 status = bmi_get_target_info(&targ_info, scn);
398 if (status != CDF_STATUS_SUCCESS)
399 return status;
400
401 BMI_DBG("%s: target type 0x%x, target ver 0x%x", __func__,
402 targ_info.target_type, targ_info.target_ver);
403 scn->target_type = targ_info.target_type;
404 scn->target_version = targ_info.target_ver;
405
406 if (cnss_get_fw_image(&image_desc_info) != 0) {
407 BMI_ERR("Failed to get fw image");
408 return CDF_STATUS_E_FAILURE;
409 }
410
411 status = bmi_load_image(image_desc_info.bdata_addr,
412 image_desc_info.bdata_size,
413 scn);
414 if (status != CDF_STATUS_SUCCESS) {
415 BMI_ERR("Load board data failed! status:%d", status);
416 return status;
417 }
418
419 status = bmi_load_image(image_desc_info.fw_addr,
420 image_desc_info.fw_size,
421 scn);
422 if (status != CDF_STATUS_SUCCESS)
423 BMI_ERR("Load fw image failed! status:%d", status);
424
425 return status;
426}
427
428CDF_STATUS bmi_firmware_download(struct ol_softc *scn)
429{
430 CDF_STATUS status;
431
432 if (IHELIUM_NO_BMI)
433 return CDF_STATUS_SUCCESS;
434
435 status = bmi_init(scn);
436 if (status != CDF_STATUS_SUCCESS) {
437 BMI_ERR("BMI_INIT Failed status:%d", status);
438 goto end;
439 }
440
441 status = bmi_enable(scn);
442 if (status != CDF_STATUS_SUCCESS) {
443 BMI_ERR("BMI_ENABLE failed status:%d\n", status);
444 goto err_bmi_enable;
445 }
446
447 return status;
448err_bmi_enable:
449 bmi_cleanup(scn);
450end:
451 return status;
452}