xref: /wlan-driver/qcacld-3.0/core/bmi/src/bmi.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name #include "i_bmi.h"
21*5113495bSYour Name #include "cds_api.h"
22*5113495bSYour Name 
23*5113495bSYour Name /* APIs visible to the driver */
24*5113495bSYour Name 
bmi_init(struct ol_context * ol_ctx)25*5113495bSYour Name QDF_STATUS bmi_init(struct ol_context *ol_ctx)
26*5113495bSYour Name {
27*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
28*5113495bSYour Name 	struct hif_opaque_softc *scn = ol_ctx->scn;
29*5113495bSYour Name 	qdf_device_t qdf_dev = ol_ctx->qdf_dev;
30*5113495bSYour Name 
31*5113495bSYour Name 	if (!scn) {
32*5113495bSYour Name 		BMI_ERR("Invalid scn Context");
33*5113495bSYour Name 		bmi_assert(0);
34*5113495bSYour Name 		return QDF_STATUS_NOT_INITIALIZED;
35*5113495bSYour Name 	}
36*5113495bSYour Name 
37*5113495bSYour Name 	if (!qdf_dev->dev) {
38*5113495bSYour Name 		BMI_ERR("%s: Invalid Device Pointer", __func__);
39*5113495bSYour Name 		return QDF_STATUS_NOT_INITIALIZED;
40*5113495bSYour Name 	}
41*5113495bSYour Name 
42*5113495bSYour Name 	info->bmi_done = false;
43*5113495bSYour Name 
44*5113495bSYour Name 	if (!info->bmi_cmd_buff) {
45*5113495bSYour Name 		info->bmi_cmd_buff =
46*5113495bSYour Name 			qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev,
47*5113495bSYour Name 						 MAX_BMI_CMDBUF_SZ,
48*5113495bSYour Name 						 &info->bmi_cmd_da);
49*5113495bSYour Name 		if (!info->bmi_cmd_buff) {
50*5113495bSYour Name 			BMI_ERR("No Memory for BMI Command");
51*5113495bSYour Name 			return QDF_STATUS_E_NOMEM;
52*5113495bSYour Name 		}
53*5113495bSYour Name 	}
54*5113495bSYour Name 
55*5113495bSYour Name 	if (!info->bmi_rsp_buff) {
56*5113495bSYour Name 		info->bmi_rsp_buff =
57*5113495bSYour Name 			qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev,
58*5113495bSYour Name 						 MAX_BMI_CMDBUF_SZ,
59*5113495bSYour Name 						 &info->bmi_rsp_da);
60*5113495bSYour Name 		if (!info->bmi_rsp_buff) {
61*5113495bSYour Name 			BMI_ERR("No Memory for BMI Response");
62*5113495bSYour Name 			goto end;
63*5113495bSYour Name 		}
64*5113495bSYour Name 	}
65*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
66*5113495bSYour Name end:
67*5113495bSYour Name 	qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ,
68*5113495bSYour Name 				 info->bmi_cmd_buff, info->bmi_cmd_da, 0);
69*5113495bSYour Name 	info->bmi_cmd_buff = NULL;
70*5113495bSYour Name 	return QDF_STATUS_E_NOMEM;
71*5113495bSYour Name }
72*5113495bSYour Name 
bmi_cleanup(struct ol_context * ol_ctx)73*5113495bSYour Name void bmi_cleanup(struct ol_context *ol_ctx)
74*5113495bSYour Name {
75*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
76*5113495bSYour Name 	qdf_device_t qdf_dev;
77*5113495bSYour Name 
78*5113495bSYour Name 	if (!info || !ol_ctx) {
79*5113495bSYour Name 		BMI_WARN("%s: no bmi to cleanup", __func__);
80*5113495bSYour Name 		return;
81*5113495bSYour Name 	}
82*5113495bSYour Name 
83*5113495bSYour Name 	qdf_dev = ol_ctx->qdf_dev;
84*5113495bSYour Name 	if (!qdf_dev || !qdf_dev->dev) {
85*5113495bSYour Name 		BMI_ERR("%s: Invalid Device Pointer", __func__);
86*5113495bSYour Name 		return;
87*5113495bSYour Name 	}
88*5113495bSYour Name 
89*5113495bSYour Name 	if (info->bmi_cmd_buff) {
90*5113495bSYour Name 		qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
91*5113495bSYour Name 					MAX_BMI_CMDBUF_SZ,
92*5113495bSYour Name 				    info->bmi_cmd_buff, info->bmi_cmd_da, 0);
93*5113495bSYour Name 		info->bmi_cmd_buff = NULL;
94*5113495bSYour Name 		info->bmi_cmd_da = 0;
95*5113495bSYour Name 	}
96*5113495bSYour Name 
97*5113495bSYour Name 	if (info->bmi_rsp_buff) {
98*5113495bSYour Name 		qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
99*5113495bSYour Name 					MAX_BMI_CMDBUF_SZ,
100*5113495bSYour Name 				    info->bmi_rsp_buff, info->bmi_rsp_da, 0);
101*5113495bSYour Name 		info->bmi_rsp_buff = NULL;
102*5113495bSYour Name 		info->bmi_rsp_da = 0;
103*5113495bSYour Name 	}
104*5113495bSYour Name }
105*5113495bSYour Name 
106*5113495bSYour Name /**
107*5113495bSYour Name  * bmi_done() - finish the bmi operation
108*5113495bSYour Name  * @ol_ctx: the bmi context
109*5113495bSYour Name  *
110*5113495bSYour Name  * does some sanity checking.
111*5113495bSYour Name  * exchanges one last message with firmware.
112*5113495bSYour Name  * frees some buffers.
113*5113495bSYour Name  *
114*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS if bmi isn't needed.
115*5113495bSYour Name  *	QDF_STATUS_SUCCESS if bmi finishes.
116*5113495bSYour Name  *	otherwise returns failure.
117*5113495bSYour Name  */
bmi_done(struct ol_context * ol_ctx)118*5113495bSYour Name QDF_STATUS bmi_done(struct ol_context *ol_ctx)
119*5113495bSYour Name {
120*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
121*5113495bSYour Name 
122*5113495bSYour Name 	if (NO_BMI)
123*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
124*5113495bSYour Name 
125*5113495bSYour Name 	if (!ol_ctx) {
126*5113495bSYour Name 		BMI_ERR("%s: null context", __func__);
127*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
128*5113495bSYour Name 	}
129*5113495bSYour Name 	hif_claim_device(ol_ctx->scn);
130*5113495bSYour Name 
131*5113495bSYour Name 	if (!hif_needs_bmi(ol_ctx->scn))
132*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
133*5113495bSYour Name 
134*5113495bSYour Name 	status = bmi_done_local(ol_ctx);
135*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS)
136*5113495bSYour Name 		BMI_ERR("BMI_DONE Failed status:%d", status);
137*5113495bSYour Name 
138*5113495bSYour Name 	return status;
139*5113495bSYour Name }
140*5113495bSYour Name 
bmi_target_ready(struct hif_opaque_softc * scn,void * cfg_ctx)141*5113495bSYour Name void bmi_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx)
142*5113495bSYour Name {
143*5113495bSYour Name 	ol_target_ready(scn, cfg_ctx);
144*5113495bSYour Name }
145*5113495bSYour Name 
146*5113495bSYour Name static QDF_STATUS
bmi_get_target_info_message_based(struct bmi_target_info * targ_info,struct ol_context * ol_ctx)147*5113495bSYour Name bmi_get_target_info_message_based(struct bmi_target_info *targ_info,
148*5113495bSYour Name 						struct ol_context *ol_ctx)
149*5113495bSYour Name {
150*5113495bSYour Name 	int status = 0;
151*5113495bSYour Name 	struct hif_opaque_softc *scn = ol_ctx->scn;
152*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
153*5113495bSYour Name 	uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
154*5113495bSYour Name 	uint8_t *bmi_rsp_buff = info->bmi_rsp_buff;
155*5113495bSYour Name 	uint32_t cid, length;
156*5113495bSYour Name 	qdf_dma_addr_t cmd = info->bmi_cmd_da;
157*5113495bSYour Name 	qdf_dma_addr_t rsp = info->bmi_rsp_da;
158*5113495bSYour Name 
159*5113495bSYour Name 	if (!bmi_cmd_buff || !bmi_rsp_buff) {
160*5113495bSYour Name 		BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__);
161*5113495bSYour Name 		return QDF_STATUS_NOT_INITIALIZED;
162*5113495bSYour Name 	}
163*5113495bSYour Name 
164*5113495bSYour Name 	cid = BMI_GET_TARGET_INFO;
165*5113495bSYour Name 
166*5113495bSYour Name 	qdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid));
167*5113495bSYour Name 	length = sizeof(struct bmi_target_info);
168*5113495bSYour Name 
169*5113495bSYour Name 	status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, sizeof(cid),
170*5113495bSYour Name 					(uint8_t *)bmi_rsp_buff, &length,
171*5113495bSYour Name 					BMI_EXCHANGE_TIMEOUT_MS);
172*5113495bSYour Name 	if (status) {
173*5113495bSYour Name 		BMI_ERR("Failed to target info: status:%d", status);
174*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
175*5113495bSYour Name 	}
176*5113495bSYour Name 
177*5113495bSYour Name 	qdf_mem_copy(targ_info, bmi_rsp_buff, length);
178*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
179*5113495bSYour Name }
180*5113495bSYour Name 
181*5113495bSYour Name QDF_STATUS
bmi_get_target_info(struct bmi_target_info * targ_info,struct ol_context * ol_ctx)182*5113495bSYour Name bmi_get_target_info(struct bmi_target_info *targ_info,
183*5113495bSYour Name 						struct ol_context *ol_ctx)
184*5113495bSYour Name {
185*5113495bSYour Name 	struct hif_opaque_softc *scn = ol_ctx->scn;
186*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
187*5113495bSYour Name 	QDF_STATUS status;
188*5113495bSYour Name 
189*5113495bSYour Name 	if (info->bmi_done) {
190*5113495bSYour Name 		BMI_ERR("BMI Phase is Already Done");
191*5113495bSYour Name 		return QDF_STATUS_E_PERM;
192*5113495bSYour Name 	}
193*5113495bSYour Name 
194*5113495bSYour Name 	switch (hif_get_bus_type(scn)) {
195*5113495bSYour Name 	case QDF_BUS_TYPE_PCI:
196*5113495bSYour Name 	case QDF_BUS_TYPE_SNOC:
197*5113495bSYour Name 	case QDF_BUS_TYPE_USB:
198*5113495bSYour Name 		status = bmi_get_target_info_message_based(targ_info, ol_ctx);
199*5113495bSYour Name 		break;
200*5113495bSYour Name #ifdef HIF_SDIO
201*5113495bSYour Name 	case QDF_BUS_TYPE_SDIO:
202*5113495bSYour Name 		status = hif_reg_based_get_target_info(scn, targ_info);
203*5113495bSYour Name 		break;
204*5113495bSYour Name #endif
205*5113495bSYour Name 	default:
206*5113495bSYour Name 		status = QDF_STATUS_E_FAILURE;
207*5113495bSYour Name 		break;
208*5113495bSYour Name 	}
209*5113495bSYour Name 	return status;
210*5113495bSYour Name }
211*5113495bSYour Name 
bmi_download_firmware(struct ol_context * ol_ctx)212*5113495bSYour Name QDF_STATUS bmi_download_firmware(struct ol_context *ol_ctx)
213*5113495bSYour Name {
214*5113495bSYour Name 	struct hif_opaque_softc *scn;
215*5113495bSYour Name 
216*5113495bSYour Name 	if (!ol_ctx) {
217*5113495bSYour Name 		if (NO_BMI) {
218*5113495bSYour Name 			/* ol_ctx is not allocated in NO_BMI case */
219*5113495bSYour Name 			return QDF_STATUS_SUCCESS;
220*5113495bSYour Name 		}
221*5113495bSYour Name 
222*5113495bSYour Name 		BMI_ERR("ol_ctx is NULL");
223*5113495bSYour Name 		bmi_assert(0);
224*5113495bSYour Name 		return QDF_STATUS_NOT_INITIALIZED;
225*5113495bSYour Name 	}
226*5113495bSYour Name 
227*5113495bSYour Name 	scn = ol_ctx->scn;
228*5113495bSYour Name 
229*5113495bSYour Name 	if (!scn) {
230*5113495bSYour Name 		BMI_ERR("Invalid scn context");
231*5113495bSYour Name 		bmi_assert(0);
232*5113495bSYour Name 		return QDF_STATUS_NOT_INITIALIZED;
233*5113495bSYour Name 	}
234*5113495bSYour Name 
235*5113495bSYour Name 	if (!hif_needs_bmi(scn))
236*5113495bSYour Name 		return QDF_STATUS_SUCCESS;
237*5113495bSYour Name 	else
238*5113495bSYour Name 		hif_register_bmi_callbacks(scn);
239*5113495bSYour Name 
240*5113495bSYour Name 	return bmi_firmware_download(ol_ctx);
241*5113495bSYour Name }
242*5113495bSYour Name 
bmi_read_soc_register(uint32_t address,uint32_t * param,struct ol_context * ol_ctx)243*5113495bSYour Name QDF_STATUS bmi_read_soc_register(uint32_t address, uint32_t *param,
244*5113495bSYour Name 						struct ol_context *ol_ctx)
245*5113495bSYour Name {
246*5113495bSYour Name 	struct hif_opaque_softc *scn = ol_ctx->scn;
247*5113495bSYour Name 	uint32_t cid;
248*5113495bSYour Name 	int status;
249*5113495bSYour Name 	uint32_t offset, param_len;
250*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
251*5113495bSYour Name 	uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
252*5113495bSYour Name 	uint8_t *bmi_rsp_buff = info->bmi_rsp_buff;
253*5113495bSYour Name 	qdf_dma_addr_t cmd = info->bmi_cmd_da;
254*5113495bSYour Name 	qdf_dma_addr_t rsp = info->bmi_rsp_da;
255*5113495bSYour Name 
256*5113495bSYour Name 	bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
257*5113495bSYour Name 	qdf_mem_zero(bmi_cmd_buff, sizeof(cid) + sizeof(address));
258*5113495bSYour Name 	qdf_mem_zero(bmi_rsp_buff, sizeof(cid) + sizeof(address));
259*5113495bSYour Name 
260*5113495bSYour Name 	if (info->bmi_done) {
261*5113495bSYour Name 		BMI_DBG("Command disallowed");
262*5113495bSYour Name 		return QDF_STATUS_E_PERM;
263*5113495bSYour Name 	}
264*5113495bSYour Name 
265*5113495bSYour Name 	BMI_DBG("BMI Read SOC Register:device: 0x%pK, address: 0x%x",
266*5113495bSYour Name 			 scn, address);
267*5113495bSYour Name 
268*5113495bSYour Name 	cid = BMI_READ_SOC_REGISTER;
269*5113495bSYour Name 
270*5113495bSYour Name 	offset = 0;
271*5113495bSYour Name 	qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
272*5113495bSYour Name 	offset += sizeof(cid);
273*5113495bSYour Name 	qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
274*5113495bSYour Name 	offset += sizeof(address);
275*5113495bSYour Name 	param_len = sizeof(*param);
276*5113495bSYour Name 	status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
277*5113495bSYour Name 			bmi_rsp_buff, &param_len, BMI_EXCHANGE_TIMEOUT_MS);
278*5113495bSYour Name 	if (status) {
279*5113495bSYour Name 		BMI_DBG("Unable to read from the device; status:%d", status);
280*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
281*5113495bSYour Name 	}
282*5113495bSYour Name 	qdf_mem_copy(param, bmi_rsp_buff, sizeof(*param));
283*5113495bSYour Name 
284*5113495bSYour Name 	BMI_DBG("BMI Read SOC Register: Exit value: %d", *param);
285*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
286*5113495bSYour Name }
287*5113495bSYour Name 
bmi_write_soc_register(uint32_t address,uint32_t param,struct ol_context * ol_ctx)288*5113495bSYour Name QDF_STATUS bmi_write_soc_register(uint32_t address, uint32_t param,
289*5113495bSYour Name 					struct ol_context *ol_ctx)
290*5113495bSYour Name {
291*5113495bSYour Name 	struct hif_opaque_softc *scn = ol_ctx->scn;
292*5113495bSYour Name 	uint32_t cid;
293*5113495bSYour Name 	int status;
294*5113495bSYour Name 	uint32_t offset;
295*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
296*5113495bSYour Name 	uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
297*5113495bSYour Name 	uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param);
298*5113495bSYour Name 	qdf_dma_addr_t cmd = info->bmi_cmd_da;
299*5113495bSYour Name 	qdf_dma_addr_t rsp = info->bmi_rsp_da;
300*5113495bSYour Name 
301*5113495bSYour Name 	bmi_assert(BMI_COMMAND_FITS(size));
302*5113495bSYour Name 	qdf_mem_zero(bmi_cmd_buff, size);
303*5113495bSYour Name 
304*5113495bSYour Name 	if (info->bmi_done) {
305*5113495bSYour Name 		BMI_DBG("Command disallowed");
306*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
307*5113495bSYour Name 	}
308*5113495bSYour Name 
309*5113495bSYour Name 	BMI_DBG("SOC Register Write:device:0x%pK, addr:0x%x, param:%d",
310*5113495bSYour Name 						scn, address, param);
311*5113495bSYour Name 
312*5113495bSYour Name 	cid = BMI_WRITE_SOC_REGISTER;
313*5113495bSYour Name 
314*5113495bSYour Name 	offset = 0;
315*5113495bSYour Name 	qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
316*5113495bSYour Name 	offset += sizeof(cid);
317*5113495bSYour Name 	qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
318*5113495bSYour Name 	offset += sizeof(address);
319*5113495bSYour Name 	qdf_mem_copy(&(bmi_cmd_buff[offset]), &param, sizeof(param));
320*5113495bSYour Name 	offset += sizeof(param);
321*5113495bSYour Name 	status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
322*5113495bSYour Name 						NULL, NULL, 0);
323*5113495bSYour Name 	if (status) {
324*5113495bSYour Name 		BMI_ERR("Unable to write to the device: status:%d", status);
325*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
326*5113495bSYour Name 	}
327*5113495bSYour Name 
328*5113495bSYour Name 	BMI_DBG("BMI Read SOC Register: Exit");
329*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
330*5113495bSYour Name }
331*5113495bSYour Name 
332*5113495bSYour Name static QDF_STATUS
bmilz_data(uint8_t * buffer,uint32_t length,struct ol_context * ol_ctx)333*5113495bSYour Name bmilz_data(uint8_t *buffer, uint32_t length, struct ol_context *ol_ctx)
334*5113495bSYour Name {
335*5113495bSYour Name 	uint32_t cid;
336*5113495bSYour Name 	int status;
337*5113495bSYour Name 	uint32_t offset;
338*5113495bSYour Name 	uint32_t remaining, txlen;
339*5113495bSYour Name 	const uint32_t header = sizeof(cid) + sizeof(length);
340*5113495bSYour Name 	struct hif_opaque_softc *scn = ol_ctx->scn;
341*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
342*5113495bSYour Name 	uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
343*5113495bSYour Name 	qdf_dma_addr_t cmd = info->bmi_cmd_da;
344*5113495bSYour Name 	qdf_dma_addr_t rsp = info->bmi_rsp_da;
345*5113495bSYour Name 
346*5113495bSYour Name 	bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
347*5113495bSYour Name 	qdf_mem_zero(bmi_cmd_buff, BMI_DATASZ_MAX + header);
348*5113495bSYour Name 
349*5113495bSYour Name 	if (info->bmi_done) {
350*5113495bSYour Name 		BMI_ERR("Command disallowed");
351*5113495bSYour Name 		return QDF_STATUS_E_PERM;
352*5113495bSYour Name 	}
353*5113495bSYour Name 
354*5113495bSYour Name 	BMI_DBG("BMI Send LZ Data: device: 0x%pK, length: %d",
355*5113495bSYour Name 						scn, length);
356*5113495bSYour Name 
357*5113495bSYour Name 	cid = BMI_LZ_DATA;
358*5113495bSYour Name 
359*5113495bSYour Name 	remaining = length;
360*5113495bSYour Name 	while (remaining) {
361*5113495bSYour Name 		txlen = (remaining < (BMI_DATASZ_MAX - header)) ?
362*5113495bSYour Name 			remaining : (BMI_DATASZ_MAX - header);
363*5113495bSYour Name 		offset = 0;
364*5113495bSYour Name 		qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
365*5113495bSYour Name 		offset += sizeof(cid);
366*5113495bSYour Name 		qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
367*5113495bSYour Name 		offset += sizeof(txlen);
368*5113495bSYour Name 		qdf_mem_copy(&(bmi_cmd_buff[offset]),
369*5113495bSYour Name 			&buffer[length - remaining], txlen);
370*5113495bSYour Name 		offset += txlen;
371*5113495bSYour Name 		status = hif_exchange_bmi_msg(scn, cmd, rsp,
372*5113495bSYour Name 						bmi_cmd_buff, offset,
373*5113495bSYour Name 						NULL, NULL, 0);
374*5113495bSYour Name 		if (status) {
375*5113495bSYour Name 			BMI_ERR("Failed to write to the device: status:%d",
376*5113495bSYour Name 								status);
377*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
378*5113495bSYour Name 		}
379*5113495bSYour Name 		remaining -= txlen;
380*5113495bSYour Name 	}
381*5113495bSYour Name 
382*5113495bSYour Name 	BMI_DBG("BMI LZ Data: Exit");
383*5113495bSYour Name 
384*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
385*5113495bSYour Name }
386*5113495bSYour Name 
bmi_sign_stream_start(uint32_t address,uint8_t * buffer,uint32_t length,struct ol_context * ol_ctx)387*5113495bSYour Name QDF_STATUS bmi_sign_stream_start(uint32_t address, uint8_t *buffer,
388*5113495bSYour Name 				 uint32_t length, struct ol_context *ol_ctx)
389*5113495bSYour Name {
390*5113495bSYour Name 	uint32_t cid;
391*5113495bSYour Name 	int status;
392*5113495bSYour Name 	uint32_t offset;
393*5113495bSYour Name 	const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length);
394*5113495bSYour Name 	uint8_t aligned_buf[BMI_DATASZ_MAX + 4];
395*5113495bSYour Name 	uint8_t *src;
396*5113495bSYour Name 	struct hif_opaque_softc *scn = ol_ctx->scn;
397*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
398*5113495bSYour Name 	uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
399*5113495bSYour Name 	uint32_t remaining, txlen;
400*5113495bSYour Name 	qdf_dma_addr_t cmd = info->bmi_cmd_da;
401*5113495bSYour Name 	qdf_dma_addr_t rsp = info->bmi_rsp_da;
402*5113495bSYour Name 
403*5113495bSYour Name 	bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
404*5113495bSYour Name 	qdf_mem_zero(bmi_cmd_buff, BMI_DATASZ_MAX + header);
405*5113495bSYour Name 
406*5113495bSYour Name 	if (info->bmi_done) {
407*5113495bSYour Name 		BMI_ERR("Command disallowed");
408*5113495bSYour Name 		return QDF_STATUS_E_PERM;
409*5113495bSYour Name 	}
410*5113495bSYour Name 
411*5113495bSYour Name 	BMI_ERR("Sign Stream start:device:0x%pK, addr:0x%x, length:%d",
412*5113495bSYour Name 						scn, address, length);
413*5113495bSYour Name 
414*5113495bSYour Name 	cid = BMI_SIGN_STREAM_START;
415*5113495bSYour Name 	remaining = length;
416*5113495bSYour Name 	while (remaining) {
417*5113495bSYour Name 		src = &buffer[length - remaining];
418*5113495bSYour Name 		if (remaining < (BMI_DATASZ_MAX - header)) {
419*5113495bSYour Name 			if (remaining & 0x3) {
420*5113495bSYour Name 				memcpy(aligned_buf, src, remaining);
421*5113495bSYour Name 				remaining = remaining + (4 - (remaining & 0x3));
422*5113495bSYour Name 				src = aligned_buf;
423*5113495bSYour Name 			}
424*5113495bSYour Name 			txlen = remaining;
425*5113495bSYour Name 		} else {
426*5113495bSYour Name 			txlen = (BMI_DATASZ_MAX - header);
427*5113495bSYour Name 		}
428*5113495bSYour Name 
429*5113495bSYour Name 		offset = 0;
430*5113495bSYour Name 		qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
431*5113495bSYour Name 		offset += sizeof(cid);
432*5113495bSYour Name 		qdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
433*5113495bSYour Name 						sizeof(address));
434*5113495bSYour Name 		offset += sizeof(offset);
435*5113495bSYour Name 		qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
436*5113495bSYour Name 		offset += sizeof(txlen);
437*5113495bSYour Name 		qdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen);
438*5113495bSYour Name 		offset += txlen;
439*5113495bSYour Name 		status = hif_exchange_bmi_msg(scn, cmd, rsp,
440*5113495bSYour Name 						bmi_cmd_buff, offset, NULL,
441*5113495bSYour Name 						NULL, BMI_EXCHANGE_TIMEOUT_MS);
442*5113495bSYour Name 		if (status) {
443*5113495bSYour Name 			BMI_ERR("Unable to write to the device: status:%d",
444*5113495bSYour Name 								status);
445*5113495bSYour Name 			return QDF_STATUS_E_FAILURE;
446*5113495bSYour Name 		}
447*5113495bSYour Name 		remaining -= txlen;
448*5113495bSYour Name 	}
449*5113495bSYour Name 	BMI_DBG("BMI SIGN Stream Start: Exit");
450*5113495bSYour Name 
451*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
452*5113495bSYour Name }
453*5113495bSYour Name 
454*5113495bSYour Name static QDF_STATUS
bmilz_stream_start(uint32_t address,struct ol_context * ol_ctx)455*5113495bSYour Name bmilz_stream_start(uint32_t address, struct ol_context *ol_ctx)
456*5113495bSYour Name {
457*5113495bSYour Name 	uint32_t cid;
458*5113495bSYour Name 	int status;
459*5113495bSYour Name 	uint32_t offset;
460*5113495bSYour Name 	struct hif_opaque_softc *scn = ol_ctx->scn;
461*5113495bSYour Name 	struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
462*5113495bSYour Name 	uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
463*5113495bSYour Name 	qdf_dma_addr_t cmd = info->bmi_cmd_da;
464*5113495bSYour Name 	qdf_dma_addr_t rsp = info->bmi_rsp_da;
465*5113495bSYour Name 
466*5113495bSYour Name 	bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
467*5113495bSYour Name 	qdf_mem_zero(bmi_cmd_buff, sizeof(cid) + sizeof(address));
468*5113495bSYour Name 
469*5113495bSYour Name 	if (info->bmi_done) {
470*5113495bSYour Name 		BMI_DBG("Command disallowed");
471*5113495bSYour Name 		return QDF_STATUS_E_PERM;
472*5113495bSYour Name 	}
473*5113495bSYour Name 	BMI_DBG("BMI LZ Stream Start: (device: 0x%pK, address: 0x%x)",
474*5113495bSYour Name 						scn, address);
475*5113495bSYour Name 
476*5113495bSYour Name 	cid = BMI_LZ_STREAM_START;
477*5113495bSYour Name 	offset = 0;
478*5113495bSYour Name 	qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
479*5113495bSYour Name 	offset += sizeof(cid);
480*5113495bSYour Name 	qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
481*5113495bSYour Name 	offset += sizeof(address);
482*5113495bSYour Name 	status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
483*5113495bSYour Name 						NULL, NULL, 0);
484*5113495bSYour Name 	if (status) {
485*5113495bSYour Name 		BMI_ERR("Unable to Start LZ Stream to the device status:%d",
486*5113495bSYour Name 								status);
487*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
488*5113495bSYour Name 	}
489*5113495bSYour Name 	BMI_DBG("BMI LZ Stream: Exit");
490*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
491*5113495bSYour Name }
492*5113495bSYour Name 
493*5113495bSYour Name QDF_STATUS
bmi_fast_download(uint32_t address,uint8_t * buffer,uint32_t length,struct ol_context * ol_ctx)494*5113495bSYour Name bmi_fast_download(uint32_t address, uint8_t *buffer,
495*5113495bSYour Name 		  uint32_t length, struct ol_context *ol_ctx)
496*5113495bSYour Name {
497*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
498*5113495bSYour Name 	uint32_t last_word = 0;
499*5113495bSYour Name 	uint32_t last_word_offset = length & ~0x3;
500*5113495bSYour Name 	uint32_t unaligned_bytes = length & 0x3;
501*5113495bSYour Name 
502*5113495bSYour Name 	status = bmilz_stream_start(address, ol_ctx);
503*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS)
504*5113495bSYour Name 		goto end;
505*5113495bSYour Name 
506*5113495bSYour Name 	/* copy the last word into a zero padded buffer */
507*5113495bSYour Name 	if (unaligned_bytes)
508*5113495bSYour Name 		qdf_mem_copy(&last_word, &buffer[last_word_offset],
509*5113495bSYour Name 						unaligned_bytes);
510*5113495bSYour Name 
511*5113495bSYour Name 	status = bmilz_data(buffer, last_word_offset, ol_ctx);
512*5113495bSYour Name 
513*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS)
514*5113495bSYour Name 		goto end;
515*5113495bSYour Name 
516*5113495bSYour Name 	if (unaligned_bytes)
517*5113495bSYour Name 		status = bmilz_data((uint8_t *) &last_word, 4, ol_ctx);
518*5113495bSYour Name 
519*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS)
520*5113495bSYour Name 		/*
521*5113495bSYour Name 		 * Close compressed stream and open a new (fake) one.
522*5113495bSYour Name 		 * This serves mainly to flush Target caches.
523*5113495bSYour Name 		 */
524*5113495bSYour Name 		status = bmilz_stream_start(0x00, ol_ctx);
525*5113495bSYour Name end:
526*5113495bSYour Name 	return status;
527*5113495bSYour Name }
528*5113495bSYour Name 
529*5113495bSYour Name /**
530*5113495bSYour Name  * ol_cds_init() - API to initialize global CDS OL Context
531*5113495bSYour Name  * @qdf_dev: QDF Device
532*5113495bSYour Name  * @hif_ctx: HIF Context
533*5113495bSYour Name  *
534*5113495bSYour Name  * Return: Success/Failure
535*5113495bSYour Name  */
ol_cds_init(qdf_device_t qdf_dev,void * hif_ctx)536*5113495bSYour Name QDF_STATUS ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx)
537*5113495bSYour Name {
538*5113495bSYour Name 	struct ol_context *ol_info;
539*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
540*5113495bSYour Name 
541*5113495bSYour Name 	if (NO_BMI)
542*5113495bSYour Name 		return QDF_STATUS_SUCCESS; /* no BMI for Q6 bring up */
543*5113495bSYour Name 
544*5113495bSYour Name 	status = cds_alloc_context(QDF_MODULE_ID_BMI,
545*5113495bSYour Name 				   (void **)&ol_info, sizeof(*ol_info));
546*5113495bSYour Name 
547*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
548*5113495bSYour Name 		BMI_ERR("%s: CDS Allocation failed for ol_bmi context",
549*5113495bSYour Name 								__func__);
550*5113495bSYour Name 		return status;
551*5113495bSYour Name 	}
552*5113495bSYour Name 
553*5113495bSYour Name 	ol_info->qdf_dev = qdf_dev;
554*5113495bSYour Name 	ol_info->scn = hif_ctx;
555*5113495bSYour Name 	ol_info->tgt_def.targetdef = hif_get_targetdef(hif_ctx);
556*5113495bSYour Name 
557*5113495bSYour Name 	qdf_create_work(qdf_dev, &ol_info->ramdump_work,
558*5113495bSYour Name 			ramdump_work_handler, ol_info);
559*5113495bSYour Name 	qdf_create_work(qdf_dev, &ol_info->fw_indication_work,
560*5113495bSYour Name 			fw_indication_work_handler, ol_info);
561*5113495bSYour Name 
562*5113495bSYour Name 	qdf_wake_lock_create(&ol_info->fw_dl_wakelock,
563*5113495bSYour Name 			     "fw_download_wakelock");
564*5113495bSYour Name 
565*5113495bSYour Name 	return status;
566*5113495bSYour Name }
567*5113495bSYour Name 
568*5113495bSYour Name /**
569*5113495bSYour Name  * ol_cds_free() - API to free the global CDS OL Context
570*5113495bSYour Name  *
571*5113495bSYour Name  * Return: void
572*5113495bSYour Name  */
ol_cds_free(void)573*5113495bSYour Name void ol_cds_free(void)
574*5113495bSYour Name {
575*5113495bSYour Name 	struct ol_context *ol_info = cds_get_context(QDF_MODULE_ID_BMI);
576*5113495bSYour Name 
577*5113495bSYour Name 	if (NO_BMI)
578*5113495bSYour Name 		return;
579*5113495bSYour Name 
580*5113495bSYour Name 	qdf_wake_lock_destroy(&ol_info->fw_dl_wakelock);
581*5113495bSYour Name 	cds_free_context(QDF_MODULE_ID_BMI, ol_info);
582*5113495bSYour Name }
583