blob: 2d0783a5a41adca39e370b8ba877063f6689d24e [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
28#include "i_bmi.h"
29
30/* APIs visible to the driver */
31
32CDF_STATUS
33bmi_read_memory(uint32_t address,
34 uint8_t *buffer, uint32_t length, struct ol_softc *scn)
35{
36 uint32_t cid;
37 int status;
38 uint32_t offset;
39 uint32_t remaining, rxlen;
40 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
41 uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff;
42 uint32_t align;
43
44 if (scn->bmi_done) {
45 BMI_DBG("command disallowed");
46 return CDF_STATUS_E_PERM;
47 }
48
49 if (!scn->bmi_cmd_buff || !scn->bmi_rsp_buff) {
50 BMI_ERR("BMI Initialization hasn't done");
51 return CDF_STATUS_NOT_INITIALIZED;
52 }
53
54 bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) +
55 sizeof(address) + sizeof(length)));
56 cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + sizeof(cid) +
57 sizeof(address) + sizeof(length));
58 cdf_mem_set(bmi_rsp_buff, 0, BMI_DATASZ_MAX + sizeof(cid) +
59 sizeof(address) + sizeof(length));
60
61 BMI_DBG("BMI Read: device: 0x%p, address: 0x%x, length: %d",
62 scn, address, length);
63
64 cid = BMI_READ_MEMORY;
65 align = 0;
66 remaining = length;
67
68 while (remaining) {
69 rxlen = (remaining < BMI_DATASZ_MAX) ?
70 remaining : BMI_DATASZ_MAX;
71 offset = 0;
72 cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
73 offset += sizeof(cid);
74 cdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
75 sizeof(address));
76 offset += sizeof(address);
77 cdf_mem_copy(&(bmi_cmd_buff[offset]), &rxlen, sizeof(rxlen));
78 offset += sizeof(length);
79
80 /* note we reuse the same buffer to receive on */
81 status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset,
82 bmi_rsp_buff, &rxlen, BMI_EXCHANGE_TIMEOUT_MS);
83 if (status) {
84 BMI_ERR("Unable to read from the device");
85 return CDF_STATUS_E_FAILURE;
86 }
87 if (remaining == rxlen) {
88 cdf_mem_copy(&buffer[length - remaining + align],
89 bmi_rsp_buff, rxlen - align);
90 /* last align bytes are invalid */
91 } else {
92 cdf_mem_copy(&buffer[length - remaining + align],
93 bmi_rsp_buff, rxlen);
94 }
95 remaining -= rxlen;
96 address += rxlen;
97 }
98
99 BMI_DBG("BMI Read Memory: Exit");
100 return CDF_STATUS_SUCCESS;
101}
102
103CDF_STATUS
104bmi_write_memory(uint32_t address,
105 uint8_t *buffer, uint32_t length, struct ol_softc *scn)
106{
107 uint32_t cid;
108 int status;
109 uint32_t offset;
110 uint32_t remaining, txlen;
111 const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length);
112 uint8_t aligned_buffer[BMI_DATASZ_MAX];
113 uint8_t *src;
114 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
115
116 if (scn->bmi_done) {
117 BMI_ERR("Command disallowed");
118 return CDF_STATUS_E_PERM;
119 }
120
121 if (!bmi_cmd_buff) {
122 BMI_ERR("BMI initialization hasn't done");
123 return CDF_STATUS_E_PERM;
124 }
125
126 bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
127 cdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header);
128
129 BMI_DBG("BMI Write Memory:device: 0x%p, address: 0x%x, length: %d",
130 scn, address, length);
131
132 cid = BMI_WRITE_MEMORY;
133
134 remaining = length;
135 while (remaining) {
136 src = &buffer[length - remaining];
137 if (remaining < (BMI_DATASZ_MAX - header)) {
138 if (remaining & 3) {
139 /* align it with 4 bytes */
140 remaining = remaining + (4 - (remaining & 3));
141 memcpy(aligned_buffer, src, remaining);
142 src = aligned_buffer;
143 }
144 txlen = remaining;
145 } else {
146 txlen = (BMI_DATASZ_MAX - header);
147 }
148 offset = 0;
149 cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
150 offset += sizeof(cid);
151 cdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
152 sizeof(address));
153 offset += sizeof(address);
154 cdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
155 offset += sizeof(txlen);
156 cdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen);
157 offset += txlen;
158 status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset,
159 NULL, NULL, BMI_EXCHANGE_TIMEOUT_MS);
160 if (status) {
161 BMI_ERR("Unable to write to the device; status:%d",
162 status);
163 return CDF_STATUS_E_FAILURE;
164 }
165 remaining -= txlen;
166 address += txlen;
167 }
168
169 BMI_DBG("BMI Write Memory: Exit");
170
171 return CDF_STATUS_SUCCESS;
172}
173
174CDF_STATUS
175bmi_execute(uint32_t address, A_UINT32 *param, struct ol_softc *scn)
176{
177 uint32_t cid;
178 int status;
179 uint32_t offset;
180 uint32_t param_len;
181 uint8_t *bmi_cmd_buff = scn->bmi_cmd_buff;
182 uint8_t *bmi_rsp_buff = scn->bmi_rsp_buff;
183 uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param);
184
185 if (scn->bmi_done) {
186 BMI_ERR("Command disallowed");
187 return CDF_STATUS_E_PERM;
188 }
189
190 if (!bmi_cmd_buff || !bmi_rsp_buff) {
191 BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__);
192 return CDF_STATUS_NOT_INITIALIZED;
193 }
194
195 bmi_assert(BMI_COMMAND_FITS(size));
196 cdf_mem_set(bmi_cmd_buff, 0, size);
197 cdf_mem_set(bmi_rsp_buff, 0, size);
198
199
200 BMI_DBG("BMI Execute: device: 0x%p, address: 0x%x, param: %d",
201 scn, address, *param);
202
203 cid = BMI_EXECUTE;
204
205 offset = 0;
206 cdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
207 offset += sizeof(cid);
208 cdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
209 offset += sizeof(address);
210 cdf_mem_copy(&(bmi_cmd_buff[offset]), param, sizeof(*param));
211 offset += sizeof(*param);
212 param_len = sizeof(*param);
213 status = hif_exchange_bmi_msg(scn, bmi_cmd_buff, offset,
214 bmi_rsp_buff, &param_len, 0);
215 if (status) {
216 BMI_ERR("Unable to read from the device status:%d", status);
217 return CDF_STATUS_E_FAILURE;
218 }
219
220 cdf_mem_copy(param, bmi_rsp_buff, sizeof(*param));
221
222 BMI_DBG("BMI Execute: Exit (param: %d)", *param);
223 return CDF_STATUS_SUCCESS;
224}
225
226inline CDF_STATUS
227bmi_no_command(struct ol_softc *scn)
228{
229 return CDF_STATUS_SUCCESS;
230}
231
232CDF_STATUS
233bmi_firmware_download(struct ol_softc *scn)
234{
235 CDF_STATUS status;
236 struct bmi_target_info targ_info;
237 cdf_mem_zero(&targ_info, sizeof(targ_info));
238
239 /* Initialize BMI */
240 status = bmi_init(scn);
241 if (status != CDF_STATUS_SUCCESS) {
242 BMI_ERR("BMI Initialization Failed err:%d", status);
243 return status;
244 }
245
246 /* Get target information */
247 status = bmi_get_target_info(&targ_info, scn);
248 if (status != CDF_STATUS_SUCCESS) {
249 BMI_ERR("BMI Target Info get failed: status:%d", status);
250 return status;
251 }
252
253 scn->target_type = targ_info.target_type;
254 scn->target_version = targ_info.target_ver;
255
256 /* Configure target */
257 status = ol_configure_target(scn);
258 if (status != CDF_STATUS_SUCCESS) {
259 BMI_ERR("BMI Configure Target Failed status:%d", status);
260 return status;
261 }
262
263 status = ol_download_firmware(scn);
264 if (status != CDF_STATUS_SUCCESS)
265 BMI_ERR("BMI Download Firmware Failed Status:%d", status);
266
267 return status;
268}
269
270CDF_STATUS bmi_done_local(struct ol_softc *scn)
271{
272 int status;
273 uint32_t cid;
274
275 if (!scn) {
276 BMI_ERR("Invalid scn context");
277 bmi_assert(0);
278 return CDF_STATUS_NOT_INITIALIZED;
279 }
280
281 if (scn->bmi_done) {
282 BMI_DBG("bmi_done_local skipped");
283 return CDF_STATUS_E_PERM;
284 }
285
286 BMI_DBG("BMI Done: Enter (device: 0x%p)", scn);
287
288 scn->bmi_done = true;
289 cid = BMI_DONE;
290
291 if (!scn->bmi_cmd_buff) {
292 BMI_ERR("Invalid scn BMICmdBuff");
293 bmi_assert(0);
294 return CDF_STATUS_NOT_INITIALIZED;
295 }
296
297 cdf_mem_copy(scn->bmi_cmd_buff, &cid, sizeof(cid));
298
299 status = hif_exchange_bmi_msg(scn, scn->bmi_cmd_buff,
300 sizeof(cid), NULL, NULL, 0);
301 if (status) {
302 BMI_ERR("Failed to write to the device; status:%d", status);
303 return CDF_STATUS_E_FAILURE;
304 }
305
306 if (scn->bmi_cmd_buff) {
307 cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ,
308 scn->bmi_cmd_buff, scn->bmi_cmd_da, 0);
309 scn->bmi_cmd_buff = NULL;
310 scn->bmi_cmd_da = 0;
311 }
312
313 if (scn->bmi_rsp_buff) {
314 cdf_os_mem_free_consistent(scn->cdf_dev, MAX_BMI_CMDBUF_SZ,
315 scn->bmi_rsp_buff, scn->bmi_rsp_da, 0);
316 scn->bmi_rsp_buff = NULL;
317 scn->bmi_rsp_da = 0;
318 }
319
320 return CDF_STATUS_SUCCESS;
321}