123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- /*
- * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
- *
- * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
- *
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
- /*
- * This file was originally distributed by Qualcomm Atheros, Inc.
- * under proprietary terms before Copyright ownership was assigned
- * to the Linux Foundation.
- */
- #include "i_bmi.h"
- #include "cds_api.h"
- /* APIs visible to the driver */
- QDF_STATUS bmi_init(struct ol_context *ol_ctx)
- {
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- struct hif_opaque_softc *scn = ol_ctx->scn;
- qdf_device_t qdf_dev = ol_ctx->qdf_dev;
- if (!scn) {
- BMI_ERR("Invalid scn Context");
- bmi_assert(0);
- return QDF_STATUS_NOT_INITIALIZED;
- }
- if (!qdf_dev->dev) {
- BMI_ERR("%s: Invalid Device Pointer", __func__);
- return QDF_STATUS_NOT_INITIALIZED;
- }
- info->bmi_done = false;
- if (!info->bmi_cmd_buff) {
- info->bmi_cmd_buff =
- qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ,
- &info->bmi_cmd_da);
- if (!info->bmi_cmd_buff) {
- BMI_ERR("No Memory for BMI Command");
- return QDF_STATUS_E_NOMEM;
- }
- }
- if (!info->bmi_rsp_buff) {
- info->bmi_rsp_buff =
- qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ,
- &info->bmi_rsp_da);
- if (!info->bmi_rsp_buff) {
- BMI_ERR("No Memory for BMI Response");
- goto end;
- }
- }
- return QDF_STATUS_SUCCESS;
- end:
- qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ,
- info->bmi_cmd_buff, info->bmi_cmd_da, 0);
- info->bmi_cmd_buff = NULL;
- return QDF_STATUS_E_NOMEM;
- }
- void bmi_cleanup(struct ol_context *ol_ctx)
- {
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- qdf_device_t qdf_dev;
- if (!info || !ol_ctx) {
- BMI_WARN("%s: no bmi to cleanup", __func__);
- return;
- }
- qdf_dev = ol_ctx->qdf_dev;
- if (!qdf_dev || !qdf_dev->dev) {
- BMI_ERR("%s: Invalid Device Pointer", __func__);
- return;
- }
- if (info->bmi_cmd_buff) {
- qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
- MAX_BMI_CMDBUF_SZ,
- info->bmi_cmd_buff, info->bmi_cmd_da, 0);
- info->bmi_cmd_buff = NULL;
- info->bmi_cmd_da = 0;
- }
- if (info->bmi_rsp_buff) {
- qdf_mem_free_consistent(qdf_dev, qdf_dev->dev,
- MAX_BMI_CMDBUF_SZ,
- info->bmi_rsp_buff, info->bmi_rsp_da, 0);
- info->bmi_rsp_buff = NULL;
- info->bmi_rsp_da = 0;
- }
- }
- /**
- * bmi_done() - finish the bmi opperation
- * @ol_ctx: the bmi context
- *
- * does some sanity checking.
- * exchanges one last message with firmware.
- * frees some buffers.
- *
- * Return: QDF_STATUS_SUCCESS if bmi isn't needed.
- * QDF_STATUS_SUCCESS if bmi finishes.
- * otherwise returns failure.
- */
- QDF_STATUS bmi_done(struct ol_context *ol_ctx)
- {
- QDF_STATUS status = QDF_STATUS_SUCCESS;
- if (NO_BMI)
- return QDF_STATUS_SUCCESS;
- if (!ol_ctx) {
- BMI_ERR("%s: null context", __func__);
- return QDF_STATUS_E_NOMEM;
- }
- hif_claim_device(ol_ctx->scn);
- if (!hif_needs_bmi(ol_ctx->scn))
- return QDF_STATUS_SUCCESS;
- status = bmi_done_local(ol_ctx);
- if (status != QDF_STATUS_SUCCESS)
- BMI_ERR("BMI_DONE Failed status:%d", status);
- return status;
- }
- void bmi_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx)
- {
- ol_target_ready(scn, cfg_ctx);
- }
- static QDF_STATUS
- bmi_get_target_info_message_based(struct bmi_target_info *targ_info,
- struct ol_context *ol_ctx)
- {
- int status = 0;
- struct hif_opaque_softc *scn = ol_ctx->scn;
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
- uint8_t *bmi_rsp_buff = info->bmi_rsp_buff;
- uint32_t cid, length;
- qdf_dma_addr_t cmd = info->bmi_cmd_da;
- qdf_dma_addr_t rsp = info->bmi_rsp_da;
- if (!bmi_cmd_buff || !bmi_rsp_buff) {
- BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__);
- return QDF_STATUS_NOT_INITIALIZED;
- }
- cid = BMI_GET_TARGET_INFO;
- qdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid));
- length = sizeof(struct bmi_target_info);
- status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, sizeof(cid),
- (uint8_t *)bmi_rsp_buff, &length,
- BMI_EXCHANGE_TIMEOUT_MS);
- if (status) {
- BMI_ERR("Failed to target info: status:%d", status);
- return QDF_STATUS_E_FAILURE;
- }
- qdf_mem_copy(targ_info, bmi_rsp_buff, length);
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- bmi_get_target_info(struct bmi_target_info *targ_info,
- struct ol_context *ol_ctx)
- {
- struct hif_opaque_softc *scn = ol_ctx->scn;
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- QDF_STATUS status;
- if (info->bmi_done) {
- BMI_ERR("BMI Phase is Already Done");
- return QDF_STATUS_E_PERM;
- }
- switch (hif_get_bus_type(scn)) {
- case QDF_BUS_TYPE_PCI:
- case QDF_BUS_TYPE_SNOC:
- status = bmi_get_target_info_message_based(targ_info, ol_ctx);
- break;
- case QDF_BUS_TYPE_SDIO:
- status = hif_reg_based_get_target_info(scn, targ_info);
- break;
- default:
- status = QDF_STATUS_E_FAILURE;
- break;
- }
- return status;
- }
- QDF_STATUS bmi_download_firmware(struct ol_context *ol_ctx)
- {
- struct hif_opaque_softc *scn = ol_ctx->scn;
- if (NO_BMI || !hif_needs_bmi(scn))
- return QDF_STATUS_SUCCESS;
- if (!scn) {
- BMI_ERR("Invalid scn context");
- bmi_assert(0);
- return QDF_STATUS_NOT_INITIALIZED;
- }
- return bmi_firmware_download(ol_ctx);
- }
- QDF_STATUS bmi_read_soc_register(uint32_t address, uint32_t *param,
- struct ol_context *ol_ctx)
- {
- struct hif_opaque_softc *scn = ol_ctx->scn;
- uint32_t cid;
- int status;
- uint32_t offset, param_len;
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
- uint8_t *bmi_rsp_buff = info->bmi_rsp_buff;
- qdf_dma_addr_t cmd = info->bmi_cmd_da;
- qdf_dma_addr_t rsp = info->bmi_rsp_da;
- bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
- qdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address));
- qdf_mem_set(bmi_rsp_buff, 0, sizeof(cid) + sizeof(address));
- if (info->bmi_done) {
- BMI_DBG("Command disallowed");
- return QDF_STATUS_E_PERM;
- }
- BMI_DBG("BMI Read SOC Register:device: 0x%p, address: 0x%x",
- scn, address);
- cid = BMI_READ_SOC_REGISTER;
- offset = 0;
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
- offset += sizeof(address);
- param_len = sizeof(*param);
- status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
- bmi_rsp_buff, ¶m_len, BMI_EXCHANGE_TIMEOUT_MS);
- if (status) {
- BMI_DBG("Unable to read from the device; status:%d", status);
- return QDF_STATUS_E_FAILURE;
- }
- qdf_mem_copy(param, bmi_rsp_buff, sizeof(*param));
- BMI_DBG("BMI Read SOC Register: Exit value: %d", *param);
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS bmi_write_soc_register(uint32_t address, uint32_t param,
- struct ol_context *ol_ctx)
- {
- struct hif_opaque_softc *scn = ol_ctx->scn;
- uint32_t cid;
- int status;
- uint32_t offset;
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
- uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param);
- qdf_dma_addr_t cmd = info->bmi_cmd_da;
- qdf_dma_addr_t rsp = info->bmi_rsp_da;
- bmi_assert(BMI_COMMAND_FITS(size));
- qdf_mem_set(bmi_cmd_buff, 0, size);
- if (info->bmi_done) {
- BMI_DBG("Command disallowed");
- return QDF_STATUS_E_FAILURE;
- }
- BMI_DBG("SOC Register Write:device:0x%p, addr:0x%x, param:%d",
- scn, address, param);
- cid = BMI_WRITE_SOC_REGISTER;
- offset = 0;
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
- offset += sizeof(address);
- qdf_mem_copy(&(bmi_cmd_buff[offset]), ¶m, sizeof(param));
- offset += sizeof(param);
- status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
- NULL, NULL, 0);
- if (status) {
- BMI_ERR("Unable to write to the device: status:%d", status);
- return QDF_STATUS_E_FAILURE;
- }
- BMI_DBG("BMI Read SOC Register: Exit");
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- bmilz_data(uint8_t *buffer, uint32_t length, struct ol_context *ol_ctx)
- {
- uint32_t cid;
- int status;
- uint32_t offset;
- uint32_t remaining, txlen;
- const uint32_t header = sizeof(cid) + sizeof(length);
- struct hif_opaque_softc *scn = ol_ctx->scn;
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
- qdf_dma_addr_t cmd = info->bmi_cmd_da;
- qdf_dma_addr_t rsp = info->bmi_rsp_da;
- bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
- qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header);
- if (info->bmi_done) {
- BMI_ERR("Command disallowed");
- return QDF_STATUS_E_PERM;
- }
- BMI_DBG("BMI Send LZ Data: device: 0x%p, length: %d",
- scn, length);
- cid = BMI_LZ_DATA;
- remaining = length;
- while (remaining) {
- txlen = (remaining < (BMI_DATASZ_MAX - header)) ?
- remaining : (BMI_DATASZ_MAX - header);
- offset = 0;
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
- offset += sizeof(txlen);
- qdf_mem_copy(&(bmi_cmd_buff[offset]),
- &buffer[length - remaining], txlen);
- offset += txlen;
- status = hif_exchange_bmi_msg(scn, cmd, rsp,
- bmi_cmd_buff, offset,
- NULL, NULL, 0);
- if (status) {
- BMI_ERR("Failed to write to the device: status:%d",
- status);
- return QDF_STATUS_E_FAILURE;
- }
- remaining -= txlen;
- }
- BMI_DBG("BMI LZ Data: Exit");
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS bmi_sign_stream_start(uint32_t address, uint8_t *buffer,
- uint32_t length, struct ol_context *ol_ctx)
- {
- uint32_t cid;
- int status;
- uint32_t offset;
- const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length);
- uint8_t aligned_buf[BMI_DATASZ_MAX + 4];
- uint8_t *src;
- struct hif_opaque_softc *scn = ol_ctx->scn;
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
- uint32_t remaining, txlen;
- qdf_dma_addr_t cmd = info->bmi_cmd_da;
- qdf_dma_addr_t rsp = info->bmi_rsp_da;
- bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
- qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header);
- if (info->bmi_done) {
- BMI_ERR("Command disallowed");
- return QDF_STATUS_E_PERM;
- }
- BMI_ERR("Sign Stream start:device:0x%p, addr:0x%x, length:%d",
- scn, address, length);
- cid = BMI_SIGN_STREAM_START;
- remaining = length;
- while (remaining) {
- src = &buffer[length - remaining];
- if (remaining < (BMI_DATASZ_MAX - header)) {
- if (remaining & 0x3) {
- remaining = remaining + (4 - (remaining & 0x3));
- memcpy(aligned_buf, src, remaining);
- src = aligned_buf;
- }
- txlen = remaining;
- } else {
- txlen = (BMI_DATASZ_MAX - header);
- }
- offset = 0;
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &address,
- sizeof(address));
- offset += sizeof(offset);
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen));
- offset += sizeof(txlen);
- qdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen);
- offset += txlen;
- status = hif_exchange_bmi_msg(scn, cmd, rsp,
- bmi_cmd_buff, offset, NULL,
- NULL, BMI_EXCHANGE_TIMEOUT_MS);
- if (status) {
- BMI_ERR("Unable to write to the device: status:%d",
- status);
- return QDF_STATUS_E_FAILURE;
- }
- remaining -= txlen;
- }
- BMI_DBG("BMI SIGN Stream Start: Exit");
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- bmilz_stream_start(uint32_t address, struct ol_context *ol_ctx)
- {
- uint32_t cid;
- int status;
- uint32_t offset;
- struct hif_opaque_softc *scn = ol_ctx->scn;
- struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx);
- uint8_t *bmi_cmd_buff = info->bmi_cmd_buff;
- qdf_dma_addr_t cmd = info->bmi_cmd_da;
- qdf_dma_addr_t rsp = info->bmi_rsp_da;
- bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
- qdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address));
- if (info->bmi_done) {
- BMI_DBG("Command disallowed");
- return QDF_STATUS_E_PERM;
- }
- BMI_DBG("BMI LZ Stream Start: (device: 0x%p, address: 0x%x)",
- scn, address);
- cid = BMI_LZ_STREAM_START;
- offset = 0;
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid));
- offset += sizeof(cid);
- qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address));
- offset += sizeof(address);
- status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset,
- NULL, NULL, 0);
- if (status) {
- BMI_ERR("Unable to Start LZ Stream to the device status:%d",
- status);
- return QDF_STATUS_E_FAILURE;
- }
- BMI_DBG("BMI LZ Stream: Exit");
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS
- bmi_fast_download(uint32_t address, uint8_t *buffer,
- uint32_t length, struct ol_context *ol_ctx)
- {
- QDF_STATUS status = QDF_STATUS_E_FAILURE;
- uint32_t last_word = 0;
- uint32_t last_word_offset = length & ~0x3;
- uint32_t unaligned_bytes = length & 0x3;
- status = bmilz_stream_start(address, ol_ctx);
- if (status != QDF_STATUS_SUCCESS)
- goto end;
- /* copy the last word into a zero padded buffer */
- if (unaligned_bytes)
- qdf_mem_copy(&last_word, &buffer[last_word_offset],
- unaligned_bytes);
- status = bmilz_data(buffer, last_word_offset, ol_ctx);
- if (status != QDF_STATUS_SUCCESS)
- goto end;
- if (unaligned_bytes)
- status = bmilz_data((uint8_t *) &last_word, 4, ol_ctx);
- if (status != QDF_STATUS_SUCCESS)
- /*
- * Close compressed stream and open a new (fake) one.
- * This serves mainly to flush Target caches.
- */
- status = bmilz_stream_start(0x00, ol_ctx);
- end:
- return status;
- }
- /**
- * ol_cds_init() - API to initialize global CDS OL Context
- * @qdf_dev: QDF Device
- * @hif_ctx: HIF Context
- *
- * Return: Success/Failure
- */
- QDF_STATUS ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx)
- {
- struct ol_context *ol_info;
- QDF_STATUS status = QDF_STATUS_SUCCESS;
- if (NO_BMI)
- return QDF_STATUS_SUCCESS; /* no BMI for Q6 bring up */
- status = cds_alloc_context(cds_get_global_context(), QDF_MODULE_ID_BMI,
- (void **)&ol_info, sizeof(*ol_info));
- if (status != QDF_STATUS_SUCCESS) {
- BMI_ERR("%s: CDS Allocation failed for ol_bmi context",
- __func__);
- return status;
- }
- ol_info->qdf_dev = qdf_dev;
- ol_info->scn = hif_ctx;
- ol_info->tgt_def.targetdef = hif_get_targetdef(hif_ctx);
- qdf_create_work(qdf_dev, &ol_info->ramdump_work,
- ramdump_work_handler, ol_info);
- qdf_create_work(qdf_dev, &ol_info->fw_indication_work,
- fw_indication_work_handler, ol_info);
- return status;
- }
- /**
- * ol_cds_free() - API to free the global CDS OL Context
- *
- * Return: void
- */
- void ol_cds_free(void)
- {
- struct ol_context *ol_info = cds_get_context(QDF_MODULE_ID_BMI);
- if (NO_BMI)
- return;
- cds_free_context(cds_get_global_context(), QDF_MODULE_ID_BMI, ol_info);
- }
|