1 /*
2 * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "i_bmi.h"
20 #include "cds_api.h"
21
22 /* APIs visible to the driver */
23
24 QDF_STATUS
bmi_read_memory(uint32_t address,uint8_t * buffer,uint32_t length,struct ol_context * ol_ctx)25 bmi_read_memory(uint32_t address,
26 uint8_t *buffer, uint32_t length, struct ol_context *ol_ctx)
27 {
28 struct hif_opaque_softc *scn = ol_ctx->scn;
29 uint32_t cid;
30 int status;
31 uint32_t offset;
32 uint32_t remaining, rxlen;
33 struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
34 uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
35 uint8_t *bmi_rsp_buff = info->bmi_rsp_buff;
36 uint32_t align;
37 qdf_dma_addr_t cmd = info->bmi_cmd_da;
38 qdf_dma_addr_t rsp = info->bmi_rsp_da;
39
40 if (info->bmi_done) {
41 BMI_DBG("command disallowed");
42 return QDF_STATUS_E_PERM;
43 }
44
45 if (!info->bmi_cmd_buff || !info->bmi_rsp_buff) {
46 BMI_ERR("BMI Initialization hasn't done");
47 return QDF_STATUS_NOT_INITIALIZED;
48 }
49
50 bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) +
51 sizeof(address) + sizeof(length)));
52 qdf_mem_zero(bmi_cmd_buff, BMI_DATASZ_MAX + sizeof(cid) +
53 sizeof(address) + sizeof(length));
54 qdf_mem_zero(bmi_rsp_buff, BMI_DATASZ_MAX + sizeof(cid) +
55 sizeof(address) + sizeof(length));
56
57 cid = BMI_READ_MEMORY;
58 align = 0;
59 remaining = length;
60
61 while (remaining) {
62 rxlen = (remaining < BMI_DATASZ_MAX) ?
63 remaining : BMI_DATASZ_MAX;
64 offset = 0;
65 qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
66 offset += sizeof(cid);
67 qdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
68 sizeof(address));
69 offset += sizeof(address);
70 qdf_mem_copy(&(bmi_cmd_buff[offset]), &rxlen, sizeof(rxlen));
71 offset += sizeof(length);
72
73 /* note we reuse the same buffer to receive on */
74 status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff,
75 offset, bmi_rsp_buff, &rxlen,
76 BMI_EXCHANGE_TIMEOUT_MS);
77 if (status) {
78 BMI_ERR("Unable to read from the device");
79 return QDF_STATUS_E_FAILURE;
80 }
81 if (remaining == rxlen) {
82 qdf_mem_copy(&buffer[length - remaining + align],
83 bmi_rsp_buff, rxlen - align);
84 /* last align bytes are invalid */
85 } else {
86 qdf_mem_copy(&buffer[length - remaining + align],
87 bmi_rsp_buff, rxlen);
88 }
89 remaining -= rxlen;
90 address += rxlen;
91 }
92
93 return QDF_STATUS_SUCCESS;
94 }
95
bmi_write_memory(uint32_t address,uint8_t * buffer,uint32_t length,struct ol_context * ol_ctx)96 QDF_STATUS bmi_write_memory(uint32_t address, uint8_t *buffer, uint32_t length,
97 struct ol_context *ol_ctx)
98 {
99 struct hif_opaque_softc *scn = ol_ctx->scn;
100 uint32_t cid;
101 int status;
102 uint32_t offset;
103 uint32_t remaining, txlen;
104 const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length);
105 uint8_t aligned_buffer[BMI_DATASZ_MAX];
106 uint8_t *src;
107 struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
108 uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
109 qdf_dma_addr_t cmd = info->bmi_cmd_da;
110 qdf_dma_addr_t rsp = info->bmi_rsp_da;
111
112 if (info->bmi_done) {
113 BMI_ERR("Command disallowed");
114 return QDF_STATUS_E_PERM;
115 }
116
117 if (!bmi_cmd_buff) {
118 BMI_ERR("BMI initialization hasn't done");
119 return QDF_STATUS_E_PERM;
120 }
121
122 bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
123 qdf_mem_zero(bmi_cmd_buff, BMI_DATASZ_MAX + header);
124
125 cid = BMI_WRITE_MEMORY;
126
127 remaining = length;
128 while (remaining) {
129 src = &buffer[length - remaining];
130 if (remaining < (BMI_DATASZ_MAX - header)) {
131 if (remaining & 3) {
132 /* align it with 4 bytes */
133 remaining = remaining + (4 - (remaining & 3));
134 memcpy(aligned_buffer, src, remaining);
135 src = aligned_buffer;
136 }
137 txlen = remaining;
138 } else {
139 txlen = (BMI_DATASZ_MAX - header);
140 }
141 offset = 0;
142 qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
143 offset += sizeof(cid);
144 qdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
145 sizeof(address));
146 offset += sizeof(address);
147 qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
148 offset += sizeof(txlen);
149 qdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen);
150 offset += txlen;
151 status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff,
152 offset, NULL, NULL,
153 BMI_EXCHANGE_TIMEOUT_MS);
154 if (status) {
155 BMI_ERR("Unable to write to the device; status:%d",
156 status);
157 return QDF_STATUS_E_FAILURE;
158 }
159 remaining -= txlen;
160 address += txlen;
161 }
162
163 return QDF_STATUS_SUCCESS;
164 }
165
166 QDF_STATUS
bmi_execute(uint32_t address,A_UINT32 * param,struct ol_context * ol_ctx)167 bmi_execute(uint32_t address, A_UINT32 *param, struct ol_context *ol_ctx)
168 {
169 struct hif_opaque_softc *scn = ol_ctx->scn;
170 uint32_t cid;
171 int status;
172 uint32_t offset;
173 uint32_t param_len;
174 struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
175 uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
176 uint8_t *bmi_rsp_buff = info->bmi_rsp_buff;
177 uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param);
178 qdf_dma_addr_t cmd = info->bmi_cmd_da;
179 qdf_dma_addr_t rsp = info->bmi_rsp_da;
180
181 if (info->bmi_done) {
182 BMI_ERR("Command disallowed");
183 return QDF_STATUS_E_PERM;
184 }
185
186 if (!bmi_cmd_buff || !bmi_rsp_buff) {
187 BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__);
188 return QDF_STATUS_NOT_INITIALIZED;
189 }
190
191 bmi_assert(BMI_COMMAND_FITS(size));
192 qdf_mem_zero(bmi_cmd_buff, size);
193 qdf_mem_zero(bmi_rsp_buff, size);
194
195
196 BMI_DBG("BMI Execute: device: 0x%pK, address: 0x%x, param: %d",
197 scn, address, *param);
198
199 cid = BMI_EXECUTE;
200
201 offset = 0;
202 qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
203 offset += sizeof(cid);
204 qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
205 offset += sizeof(address);
206 qdf_mem_copy(&(bmi_cmd_buff[offset]), param, sizeof(*param));
207 offset += sizeof(*param);
208 param_len = sizeof(*param);
209 status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
210 bmi_rsp_buff, ¶m_len, 0);
211 if (status) {
212 BMI_ERR("Unable to read from the device status:%d", status);
213 return QDF_STATUS_E_FAILURE;
214 }
215
216 qdf_mem_copy(param, bmi_rsp_buff, sizeof(*param));
217
218 BMI_DBG("BMI Execute: Exit (param: %d)", *param);
219 return QDF_STATUS_SUCCESS;
220 }
221
222 inline QDF_STATUS
bmi_no_command(struct ol_context * ol_ctx)223 bmi_no_command(struct ol_context *ol_ctx)
224 {
225 return QDF_STATUS_SUCCESS;
226 }
227
228 QDF_STATUS
bmi_firmware_download(struct ol_context * ol_ctx)229 bmi_firmware_download(struct ol_context *ol_ctx)
230 {
231 struct hif_opaque_softc *scn = ol_ctx->scn;
232 QDF_STATUS status;
233 struct bmi_target_info targ_info;
234 struct hif_target_info *tgt_info = hif_get_target_info_handle(scn);
235
236 qdf_mem_zero(&targ_info, sizeof(targ_info));
237 /* Initialize BMI */
238 status = bmi_init(ol_ctx);
239 if (status != QDF_STATUS_SUCCESS) {
240 BMI_ERR("BMI Initialization Failed err:%d", status);
241 return status;
242 }
243
244 /* Get target information */
245 status = bmi_get_target_info(&targ_info, ol_ctx);
246 if (status != QDF_STATUS_SUCCESS) {
247 BMI_ERR("BMI Target Info get failed: status:%d", status);
248 return status;
249 }
250
251 tgt_info->target_type = targ_info.target_type;
252 tgt_info->target_version = targ_info.target_ver;
253 /* Configure target */
254 status = ol_configure_target(ol_ctx);
255 if (status != QDF_STATUS_SUCCESS) {
256 BMI_ERR("BMI Configure Target Failed status:%d", status);
257 return status;
258 }
259 status = ol_download_firmware(ol_ctx);
260 if (status != QDF_STATUS_SUCCESS)
261 BMI_ERR("BMI Download Firmware Failed Status:%d", status);
262
263 return status;
264 }
265
bmi_done_local(struct ol_context * ol_ctx)266 QDF_STATUS bmi_done_local(struct ol_context *ol_ctx)
267 {
268 struct hif_opaque_softc *scn = ol_ctx->scn;
269 int status;
270 uint32_t cid;
271 struct bmi_info *info;
272 qdf_device_t qdf_dev = ol_ctx->qdf_dev;
273 qdf_dma_addr_t cmd, rsp;
274
275 if (!scn) {
276 BMI_ERR("Invalid scn context");
277 bmi_assert(0);
278 return QDF_STATUS_NOT_INITIALIZED;
279 }
280
281 if (!qdf_dev->dev) {
282 BMI_ERR("%s: Invalid device pointer", __func__);
283 return QDF_STATUS_NOT_INITIALIZED;
284 }
285
286 info = GET_BMI_CONTEXT(ol_ctx);
287 if (info->bmi_done) {
288 BMI_DBG(FL("skipped"));
289 return QDF_STATUS_E_PERM;
290 }
291
292 cmd = info->bmi_cmd_da;
293 rsp = info->bmi_rsp_da;
294
295 BMI_DBG("BMI Done: Enter (device: 0x%pK)", scn);
296
297 info->bmi_done = true;
298 cid = BMI_DONE;
299
300 if (!info->bmi_cmd_buff) {
301 BMI_ERR("Invalid scn BMICmdBuff");
302 bmi_assert(0);
303 return QDF_STATUS_NOT_INITIALIZED;
304 }
305
306 qdf_mem_copy(info->bmi_cmd_buff, &cid, sizeof(cid));
307
308 status = hif_exchange_bmi_msg(scn, cmd, rsp, info->bmi_cmd_buff,
309 sizeof(cid), NULL, NULL, 0);
310 if (status) {
311 BMI_ERR("Failed to write to the device; status:%d", status);
312 return QDF_STATUS_E_FAILURE;
313 }
314
315 if (info->bmi_cmd_buff) {
316 qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
317 MAX_BMI_CMDBUF_SZ,
318 info->bmi_cmd_buff, info->bmi_cmd_da, 0);
319 info->bmi_cmd_buff = NULL;
320 info->bmi_cmd_da = 0;
321 }
322
323 if (info->bmi_rsp_buff) {
324 qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
325 MAX_BMI_CMDBUF_SZ,
326 info->bmi_rsp_buff, info->bmi_rsp_da, 0);
327 info->bmi_rsp_buff = NULL;
328 info->bmi_rsp_da = 0;
329 }
330
331 return QDF_STATUS_SUCCESS;
332 }
333