| Index: chromeos/drivers/ath6kl/bmi/src/bmi.c
|
| diff --git a/chromeos/drivers/ath6kl/bmi/src/bmi.c b/chromeos/drivers/ath6kl/bmi/src/bmi.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c83afe020b1b2dd4c47da81adefa8b3e859db446
|
| --- /dev/null
|
| +++ b/chromeos/drivers/ath6kl/bmi/src/bmi.c
|
| @@ -0,0 +1,983 @@
|
| +//------------------------------------------------------------------------------
|
| +// <copyright file="bmi.c" company="Atheros">
|
| +// Copyright (c) 2004-2008 Atheros Corporation. All rights reserved.
|
| +//
|
| +// This program is free software; you can redistribute it and/or modify
|
| +// it under the terms of the GNU General Public License version 2 as
|
| +// published by the Free Software Foundation;
|
| +//
|
| +// Software distributed under the License is distributed on an "AS
|
| +// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
| +// implied. See the License for the specific language governing
|
| +// rights and limitations under the License.
|
| +//
|
| +//
|
| +//------------------------------------------------------------------------------
|
| +//==============================================================================
|
| +//
|
| +// Author(s): ="Atheros"
|
| +//==============================================================================
|
| +
|
| +#include "hif.h"
|
| +#include "bmi.h"
|
| +#include "htc_api.h"
|
| +#include "bmi_internal.h"
|
| +
|
| +#ifdef DEBUG
|
| +static ATH_DEBUG_MASK_DESCRIPTION bmi_debug_desc[] = {
|
| + { ATH_DEBUG_BMI , "BMI Tracing"},
|
| +};
|
| +
|
| +ATH_DEBUG_INSTANTIATE_MODULE_VAR(bmi,
|
| + "bmi",
|
| + "Boot Manager Interface",
|
| + ATH_DEBUG_MASK_DEFAULTS,
|
| + ATH_DEBUG_DESCRIPTION_COUNT(bmi_debug_desc),
|
| + bmi_debug_desc);
|
| +
|
| +#endif
|
| +
|
| +/*
|
| +Although we had envisioned BMI to run on top of HTC, this is not how the
|
| +final implementation ended up. On the Target side, BMI is a part of the BSP
|
| +and does not use the HTC protocol nor even DMA -- it is intentionally kept
|
| +very simple.
|
| +*/
|
| +
|
| +static A_BOOL pendingEventsFuncCheck = FALSE;
|
| +static A_UINT32 *pBMICmdCredits;
|
| +static A_UCHAR *pBMICmdBuf;
|
| +#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \
|
| + sizeof(A_UINT32) /* cmd */ + \
|
| + sizeof(A_UINT32) /* addr */ + \
|
| + sizeof(A_UINT32))/* length */
|
| +#define BMI_COMMAND_FITS(sz) ((sz) <= MAX_BMI_CMDBUF_SZ)
|
| +
|
| +/* APIs visible to the driver */
|
| +void
|
| +BMIInit(void)
|
| +{
|
| + bmiDone = FALSE;
|
| + pendingEventsFuncCheck = FALSE;
|
| +
|
| + /*
|
| + * On some platforms, it's not possible to DMA to a static variable
|
| + * in a device driver (e.g. Linux loadable driver module).
|
| + * So we need to A_MALLOC space for "command credits" and for commands.
|
| + *
|
| + * Note: implicitly relies on A_MALLOC to provide a buffer that is
|
| + * suitable for DMA (or PIO). This buffer will be passed down the
|
| + * bus stack.
|
| + */
|
| + if (!pBMICmdCredits) {
|
| + pBMICmdCredits = (A_UINT32 *)A_MALLOC_NOWAIT(4);
|
| + A_ASSERT(pBMICmdCredits);
|
| + }
|
| +
|
| + if (!pBMICmdBuf) {
|
| + pBMICmdBuf = (A_UCHAR *)A_MALLOC_NOWAIT(MAX_BMI_CMDBUF_SZ);
|
| + A_ASSERT(pBMICmdBuf);
|
| + }
|
| +
|
| + A_REGISTER_MODULE_DEBUG_INFO(bmi);
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIDone(HIF_DEVICE *device)
|
| +{
|
| + A_STATUS status;
|
| + A_UINT32 cid;
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF (ATH_DEBUG_BMI, ("BMIDone skipped\n"));
|
| + return A_OK;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Enter (device: 0x%p)\n", device));
|
| + bmiDone = TRUE;
|
| + cid = BMI_DONE;
|
| +
|
| + status = bmiBufferSend(device, (A_UCHAR *)&cid, sizeof(cid));
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + if (pBMICmdCredits) {
|
| + A_FREE(pBMICmdCredits);
|
| + pBMICmdCredits = NULL;
|
| + }
|
| +
|
| + if (pBMICmdBuf) {
|
| + A_FREE(pBMICmdBuf);
|
| + pBMICmdBuf = NULL;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Done: Exit\n"));
|
| +
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIGetTargetInfo(HIF_DEVICE *device, struct bmi_target_info *targ_info)
|
| +{
|
| + A_STATUS status;
|
| + A_UINT32 cid;
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Enter (device: 0x%p)\n", device));
|
| + cid = BMI_GET_TARGET_INFO;
|
| +
|
| + status = bmiBufferSend(device, (A_UCHAR *)&cid, sizeof(cid));
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + status = bmiBufferReceive(device, (A_UCHAR *)&targ_info->target_ver,
|
| + sizeof(targ_info->target_ver), TRUE);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Version from the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + if (targ_info->target_ver == TARGET_VERSION_SENTINAL) {
|
| + /* Determine how many bytes are in the Target's targ_info */
|
| + status = bmiBufferReceive(device, (A_UCHAR *)&targ_info->target_info_byte_count,
|
| + sizeof(targ_info->target_info_byte_count), TRUE);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info Byte Count from the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + /*
|
| + * The Target's targ_info doesn't match the Host's targ_info.
|
| + * We need to do some backwards compatibility work to make this OK.
|
| + */
|
| + A_ASSERT(targ_info->target_info_byte_count == sizeof(*targ_info));
|
| +
|
| + /* Read the remainder of the targ_info */
|
| + status = bmiBufferReceive(device,
|
| + ((A_UCHAR *)targ_info)+sizeof(targ_info->target_info_byte_count),
|
| + sizeof(*targ_info)-sizeof(targ_info->target_info_byte_count), TRUE);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read Target Info (%d bytes) from the device\n",
|
| + targ_info->target_info_byte_count));
|
| + return A_ERROR;
|
| + }
|
| + } else {
|
| + /*
|
| + * Target must be an AR6001 whose firmware does not
|
| + * support BMI_GET_TARGET_INFO. Construct the data
|
| + * that it would have sent.
|
| + */
|
| + targ_info->target_info_byte_count=sizeof(*targ_info);
|
| + targ_info->target_type=TARGET_TYPE_AR6001;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n",
|
| + targ_info->target_ver, targ_info->target_type));
|
| +
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIReadMemory(HIF_DEVICE *device,
|
| + A_UINT32 address,
|
| + A_UCHAR *buffer,
|
| + A_UINT32 length)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| + A_UINT32 remaining, rxlen;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length)));
|
| + memset (pBMICmdBuf, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(address) + sizeof(length));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI Read Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n",
|
| + device, address, length));
|
| +
|
| + cid = BMI_READ_MEMORY;
|
| +
|
| + remaining = length;
|
| +
|
| + while (remaining)
|
| + {
|
| + rxlen = (remaining < BMI_DATASZ_MAX) ? remaining : BMI_DATASZ_MAX;
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &address, sizeof(address));
|
| + offset += sizeof(address);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &rxlen, sizeof(rxlen));
|
| + offset += sizeof(length);
|
| +
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| + status = bmiBufferReceive(device, pBMICmdBuf, rxlen, TRUE);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
|
| + return A_ERROR;
|
| + }
|
| + A_MEMCPY(&buffer[length - remaining], pBMICmdBuf, rxlen);
|
| + remaining -= rxlen; address += rxlen;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read Memory: Exit\n"));
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIWriteMemory(HIF_DEVICE *device,
|
| + A_UINT32 address,
|
| + A_UCHAR *buffer,
|
| + A_UINT32 length)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| + A_UINT32 remaining, txlen;
|
| + const A_UINT32 header = sizeof(cid) + sizeof(address) + sizeof(length);
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header));
|
| + memset (pBMICmdBuf, 0, BMI_DATASZ_MAX + header);
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI Write Memory: Enter (device: 0x%p, address: 0x%x, length: %d)\n",
|
| + device, address, length));
|
| +
|
| + cid = BMI_WRITE_MEMORY;
|
| +
|
| + remaining = length;
|
| + while (remaining)
|
| + {
|
| + txlen = (remaining < (BMI_DATASZ_MAX - header)) ?
|
| + remaining : (BMI_DATASZ_MAX - header);
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &address, sizeof(address));
|
| + offset += sizeof(address);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &txlen, sizeof(txlen));
|
| + offset += sizeof(txlen);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &buffer[length - remaining], txlen);
|
| + offset += txlen;
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| + remaining -= txlen; address += txlen;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Write Memory: Exit\n"));
|
| +
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIExecute(HIF_DEVICE *device,
|
| + A_UINT32 address,
|
| + A_UINT32 *param)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address) + sizeof(param)));
|
| + memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address) + sizeof(param));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI Execute: Enter (device: 0x%p, address: 0x%x, param: %d)\n",
|
| + device, address, *param));
|
| +
|
| + cid = BMI_EXECUTE;
|
| +
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &address, sizeof(address));
|
| + offset += sizeof(address);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), param, sizeof(*param));
|
| + offset += sizeof(*param);
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*param), FALSE);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + A_MEMCPY(param, pBMICmdBuf, sizeof(*param));
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Execute: Exit (param: %d)\n", *param));
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMISetAppStart(HIF_DEVICE *device,
|
| + A_UINT32 address)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
|
| + memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI Set App Start: Enter (device: 0x%p, address: 0x%x)\n",
|
| + device, address));
|
| +
|
| + cid = BMI_SET_APP_START;
|
| +
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &address, sizeof(address));
|
| + offset += sizeof(address);
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Set App Start: Exit\n"));
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIReadSOCRegister(HIF_DEVICE *device,
|
| + A_UINT32 address,
|
| + A_UINT32 *param)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
|
| + memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI Read SOC Register: Enter (device: 0x%p, address: 0x%x)\n",
|
| + device, address));
|
| +
|
| + cid = BMI_READ_SOC_REGISTER;
|
| +
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &address, sizeof(address));
|
| + offset += sizeof(address);
|
| +
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*param), TRUE);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
|
| + return A_ERROR;
|
| + }
|
| + A_MEMCPY(param, pBMICmdBuf, sizeof(*param));
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit (value: %d)\n", *param));
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIWriteSOCRegister(HIF_DEVICE *device,
|
| + A_UINT32 address,
|
| + A_UINT32 param)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address) + sizeof(param)));
|
| + memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address) + sizeof(param));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI Write SOC Register: Enter (device: 0x%p, address: 0x%x, param: %d)\n",
|
| + device, address, param));
|
| +
|
| + cid = BMI_WRITE_SOC_REGISTER;
|
| +
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &address, sizeof(address));
|
| + offset += sizeof(address);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), ¶m, sizeof(param));
|
| + offset += sizeof(param);
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Read SOC Register: Exit\n"));
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIrompatchInstall(HIF_DEVICE *device,
|
| + A_UINT32 ROM_addr,
|
| + A_UINT32 RAM_addr,
|
| + A_UINT32 nbytes,
|
| + A_UINT32 do_activate,
|
| + A_UINT32 *rompatch_id)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) +
|
| + sizeof(nbytes) + sizeof(do_activate)));
|
| + memset(pBMICmdBuf, 0, sizeof(cid) + sizeof(ROM_addr) + sizeof(RAM_addr) +
|
| + sizeof(nbytes) + sizeof(do_activate));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI rompatch Install: Enter (device: 0x%p, ROMaddr: 0x%x, RAMaddr: 0x%x length: %d activate: %d)\n",
|
| + device, ROM_addr, RAM_addr, nbytes, do_activate));
|
| +
|
| + cid = BMI_ROMPATCH_INSTALL;
|
| +
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &ROM_addr, sizeof(ROM_addr));
|
| + offset += sizeof(ROM_addr);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &RAM_addr, sizeof(RAM_addr));
|
| + offset += sizeof(RAM_addr);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &nbytes, sizeof(nbytes));
|
| + offset += sizeof(nbytes);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &do_activate, sizeof(do_activate));
|
| + offset += sizeof(do_activate);
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + status = bmiBufferReceive(device, pBMICmdBuf, sizeof(*rompatch_id), TRUE);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read from the device\n"));
|
| + return A_ERROR;
|
| + }
|
| + A_MEMCPY(rompatch_id, pBMICmdBuf, sizeof(*rompatch_id));
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch Install: (rompatch_id=%d)\n", *rompatch_id));
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIrompatchUninstall(HIF_DEVICE *device,
|
| + A_UINT32 rompatch_id)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(rompatch_id)));
|
| + memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(rompatch_id));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI rompatch Uninstall: Enter (device: 0x%p, rompatch_id: %d)\n",
|
| + device, rompatch_id));
|
| +
|
| + cid = BMI_ROMPATCH_UNINSTALL;
|
| +
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &rompatch_id, sizeof(rompatch_id));
|
| + offset += sizeof(rompatch_id);
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI rompatch UNinstall: (rompatch_id=0x%x)\n", rompatch_id));
|
| + return A_OK;
|
| +}
|
| +
|
| +static A_STATUS
|
| +_BMIrompatchChangeActivation(HIF_DEVICE *device,
|
| + A_UINT32 rompatch_count,
|
| + A_UINT32 *rompatch_list,
|
| + A_UINT32 do_activate)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| + A_UINT32 length;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count)));
|
| + memset(pBMICmdBuf, 0, BMI_DATASZ_MAX + sizeof(cid) + sizeof(rompatch_count));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI Change rompatch Activation: Enter (device: 0x%p, count: %d)\n",
|
| + device, rompatch_count));
|
| +
|
| + cid = do_activate ? BMI_ROMPATCH_ACTIVATE : BMI_ROMPATCH_DEACTIVATE;
|
| +
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &rompatch_count, sizeof(rompatch_count));
|
| + offset += sizeof(rompatch_count);
|
| + length = rompatch_count * sizeof(*rompatch_list);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), rompatch_list, length);
|
| + offset += length;
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI Change rompatch Activation: Exit\n"));
|
| +
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIrompatchActivate(HIF_DEVICE *device,
|
| + A_UINT32 rompatch_count,
|
| + A_UINT32 *rompatch_list)
|
| +{
|
| + return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 1);
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIrompatchDeactivate(HIF_DEVICE *device,
|
| + A_UINT32 rompatch_count,
|
| + A_UINT32 *rompatch_list)
|
| +{
|
| + return _BMIrompatchChangeActivation(device, rompatch_count, rompatch_list, 0);
|
| +}
|
| +
|
| +A_STATUS
|
| +BMILZData(HIF_DEVICE *device,
|
| + A_UCHAR *buffer,
|
| + A_UINT32 length)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| + A_UINT32 remaining, txlen;
|
| + const A_UINT32 header = sizeof(cid) + sizeof(length);
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(BMI_DATASZ_MAX+header));
|
| + memset (pBMICmdBuf, 0, BMI_DATASZ_MAX+header);
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI Send LZ Data: Enter (device: 0x%p, length: %d)\n",
|
| + device, length));
|
| +
|
| + cid = BMI_LZ_DATA;
|
| +
|
| + remaining = length;
|
| + while (remaining)
|
| + {
|
| + txlen = (remaining < (BMI_DATASZ_MAX - header)) ?
|
| + remaining : (BMI_DATASZ_MAX - header);
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &txlen, sizeof(txlen));
|
| + offset += sizeof(txlen);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &buffer[length - remaining], txlen);
|
| + offset += txlen;
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to write to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| + remaining -= txlen;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI LZ Data: Exit\n"));
|
| +
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMILZStreamStart(HIF_DEVICE *device,
|
| + A_UINT32 address)
|
| +{
|
| + A_UINT32 cid;
|
| + A_STATUS status;
|
| + A_UINT32 offset;
|
| +
|
| + A_ASSERT(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address)));
|
| + memset (pBMICmdBuf, 0, sizeof(cid) + sizeof(address));
|
| +
|
| + if (bmiDone) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Command disallowed\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI,
|
| + ("BMI LZ Stream Start: Enter (device: 0x%p, address: 0x%x)\n",
|
| + device, address));
|
| +
|
| + cid = BMI_LZ_STREAM_START;
|
| + offset = 0;
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &cid, sizeof(cid));
|
| + offset += sizeof(cid);
|
| + A_MEMCPY(&(pBMICmdBuf[offset]), &address, sizeof(address));
|
| + offset += sizeof(address);
|
| + status = bmiBufferSend(device, pBMICmdBuf, offset);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to Start LZ Stream to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, ("BMI LZ Stream Start: Exit\n"));
|
| +
|
| + return A_OK;
|
| +}
|
| +
|
| +/* BMI Access routines */
|
| +A_STATUS
|
| +bmiBufferSend(HIF_DEVICE *device,
|
| + A_UCHAR *buffer,
|
| + A_UINT32 length)
|
| +{
|
| + A_STATUS status;
|
| + A_UINT32 timeout;
|
| + A_UINT32 address;
|
| + A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX];
|
| +
|
| + HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
|
| + &mboxAddress[0], sizeof(mboxAddress));
|
| +
|
| + *pBMICmdCredits = 0;
|
| + timeout = BMI_COMMUNICATION_TIMEOUT;
|
| +
|
| + while(timeout-- && !(*pBMICmdCredits)) {
|
| + /* Read the counter register to get the command credits */
|
| + address = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
|
| + /* hit the credit counter with a 4-byte access, the first byte read will hit the counter and cause
|
| + * a decrement, while the remaining 3 bytes has no effect. The rationale behind this is to
|
| + * make all HIF accesses 4-byte aligned */
|
| + status = HIFReadWrite(device, address, (A_UINT8 *)pBMICmdCredits, 4,
|
| + HIF_RD_SYNC_BYTE_INC, NULL);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to decrement the command credit count register\n"));
|
| + return A_ERROR;
|
| + }
|
| + /* the counter is only 8=bits, ignore anything in the upper 3 bytes */
|
| + (*pBMICmdCredits) &= 0xFF;
|
| + }
|
| +
|
| + if (*pBMICmdCredits) {
|
| + address = mboxAddress[ENDPOINT1];
|
| + status = HIFReadWrite(device, address, buffer, length,
|
| + HIF_WR_SYNC_BYTE_INC, NULL);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to send the BMI data to the device\n"));
|
| + return A_ERROR;
|
| + }
|
| + } else {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferSend\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + return status;
|
| +}
|
| +
|
| +A_STATUS
|
| +bmiBufferReceive(HIF_DEVICE *device,
|
| + A_UCHAR *buffer,
|
| + A_UINT32 length,
|
| + A_BOOL want_timeout)
|
| +{
|
| + A_STATUS status;
|
| + A_UINT32 address;
|
| + A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX];
|
| + HIF_PENDING_EVENTS_INFO hifPendingEvents;
|
| + static HIF_PENDING_EVENTS_FUNC getPendingEventsFunc = NULL;
|
| +
|
| + if (!pendingEventsFuncCheck) {
|
| + /* see if the HIF layer implements an alternative function to get pending events
|
| + * do this only once! */
|
| + HIFConfigureDevice(device,
|
| + HIF_DEVICE_GET_PENDING_EVENTS_FUNC,
|
| + &getPendingEventsFunc,
|
| + sizeof(getPendingEventsFunc));
|
| + pendingEventsFuncCheck = TRUE;
|
| + }
|
| +
|
| + HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
|
| + &mboxAddress[0], sizeof(mboxAddress));
|
| +
|
| + /*
|
| + * During normal bootup, small reads may be required.
|
| + * Rather than issue an HIF Read and then wait as the Target
|
| + * adds successive bytes to the FIFO, we wait here until
|
| + * we know that response data is available.
|
| + *
|
| + * This allows us to cleanly timeout on an unexpected
|
| + * Target failure rather than risk problems at the HIF level. In
|
| + * particular, this avoids SDIO timeouts and possibly garbage
|
| + * data on some host controllers. And on an interconnect
|
| + * such as Compact Flash (as well as some SDIO masters) which
|
| + * does not provide any indication on data timeout, it avoids
|
| + * a potential hang or garbage response.
|
| + *
|
| + * Synchronization is more difficult for reads larger than the
|
| + * size of the MBOX FIFO (128B), because the Target is unable
|
| + * to push the 129th byte of data until AFTER the Host posts an
|
| + * HIF Read and removes some FIFO data. So for large reads the
|
| + * Host proceeds to post an HIF Read BEFORE all the data is
|
| + * actually available to read. Fortunately, large BMI reads do
|
| + * not occur in practice -- they're supported for debug/development.
|
| + *
|
| + * So Host/Target BMI synchronization is divided into these cases:
|
| + * CASE 1: length < 4
|
| + * Should not happen
|
| + *
|
| + * CASE 2: 4 <= length <= 128
|
| + * Wait for first 4 bytes to be in FIFO
|
| + * If CONSERVATIVE_BMI_READ is enabled, also wait for
|
| + * a BMI command credit, which indicates that the ENTIRE
|
| + * response is available in the the FIFO
|
| + *
|
| + * CASE 3: length > 128
|
| + * Wait for the first 4 bytes to be in FIFO
|
| + *
|
| + * For most uses, a small timeout should be sufficient and we will
|
| + * usually see a response quickly; but there may be some unusual
|
| + * (debug) cases of BMI_EXECUTE where we want an larger timeout.
|
| + * For now, we use an unbounded busy loop while waiting for
|
| + * BMI_EXECUTE.
|
| + *
|
| + * If BMI_EXECUTE ever needs to support longer-latency execution,
|
| + * especially in production, this code needs to be enhanced to sleep
|
| + * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently
|
| + * a function of Host processor speed.
|
| + */
|
| + if (length >= 4) { /* NB: Currently, always true */
|
| + /*
|
| + * NB: word_available is declared static for esoteric reasons
|
| + * having to do with protection on some OSes.
|
| + */
|
| + static A_UINT32 word_available;
|
| + A_UINT32 timeout;
|
| +
|
| + word_available = 0;
|
| + timeout = BMI_COMMUNICATION_TIMEOUT;
|
| + while((!want_timeout || timeout--) && !word_available) {
|
| +
|
| + if (getPendingEventsFunc != NULL) {
|
| + status = getPendingEventsFunc(device,
|
| + &hifPendingEvents,
|
| + NULL);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMI: Failed to get pending events \n"));
|
| + break;
|
| + }
|
| +
|
| + if (hifPendingEvents.AvailableRecvBytes >= sizeof(A_UINT32)) {
|
| + word_available = 1;
|
| + }
|
| + continue;
|
| + }
|
| +
|
| + status = HIFReadWrite(device, RX_LOOKAHEAD_VALID_ADDRESS, (A_UINT8 *)&word_available,
|
| + sizeof(word_available), HIF_RD_SYNC_BYTE_INC, NULL);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read RX_LOOKAHEAD_VALID register\n"));
|
| + return A_ERROR;
|
| + }
|
| + /* We did a 4-byte read to the same register; all we really want is one bit */
|
| + word_available &= (1 << ENDPOINT1);
|
| + }
|
| +
|
| + if (!word_available) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferReceive FIFO empty\n"));
|
| + return A_ERROR;
|
| + }
|
| + }
|
| +
|
| +#define CONSERVATIVE_BMI_READ 0
|
| +#if CONSERVATIVE_BMI_READ
|
| + /*
|
| + * This is an extra-conservative CREDIT check. It guarantees
|
| + * that ALL data is available in the FIFO before we start to
|
| + * read from the interconnect.
|
| + *
|
| + * This credit check is useless when firmware chooses to
|
| + * allow multiple outstanding BMI Command Credits, since the next
|
| + * credit will already be present. To restrict the Target to one
|
| + * BMI Command Credit, see HI_OPTION_BMI_CRED_LIMIT.
|
| + *
|
| + * And for large reads (when HI_OPTION_BMI_CRED_LIMIT is set)
|
| + * we cannot wait for the next credit because the Target's FIFO
|
| + * will not hold the entire response. So we need the Host to
|
| + * start to empty the FIFO sooner. (And again, large reads are
|
| + * not used in practice; they are for debug/development only.)
|
| + *
|
| + * For a more conservative Host implementation (which would be
|
| + * safer for a Compact Flash interconnect):
|
| + * Set CONSERVATIVE_BMI_READ (above) to 1
|
| + * Set HI_OPTION_BMI_CRED_LIMIT and
|
| + * reduce BMI_DATASZ_MAX to 32 or 64
|
| + */
|
| + if ((length > 4) && (length < 128)) { /* check against MBOX FIFO size */
|
| + A_UINT32 timeout;
|
| +
|
| + *pBMICmdCredits = 0;
|
| + timeout = BMI_COMMUNICATION_TIMEOUT;
|
| + while((!want_timeout || timeout--) && !(*pBMICmdCredits) {
|
| + /* Read the counter register to get the command credits */
|
| + address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1;
|
| + /* read the counter using a 4-byte read. Since the counter is NOT auto-decrementing,
|
| + * we can read this counter multiple times using a non-incrementing address mode.
|
| + * The rationale here is to make all HIF accesses a multiple of 4 bytes */
|
| + status = HIFReadWrite(device, address, (A_UINT8 *)pBMICmdCredits, sizeof(*pBMICmdCredits),
|
| + HIF_RD_SYNC_BYTE_FIX, NULL);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the command credit count register\n"));
|
| + return A_ERROR;
|
| + }
|
| + /* we did a 4-byte read to the same count register so mask off upper bytes */
|
| + (*pBMICmdCredits) &= 0xFF;
|
| + }
|
| +
|
| + if (!(*pBMICmdCredits)) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout- bmiBufferReceive no credit\n"));
|
| + return A_ERROR;
|
| + }
|
| + }
|
| +#endif
|
| +
|
| + address = mboxAddress[ENDPOINT1];
|
| + status = HIFReadWrite(device, address, buffer, length, HIF_RD_SYNC_BYTE_INC, NULL);
|
| + if (status != A_OK) {
|
| + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the BMI data from the device\n"));
|
| + return A_ERROR;
|
| + }
|
| +
|
| + return A_OK;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIFastDownload(HIF_DEVICE *device, A_UINT32 address, A_UCHAR *buffer, A_UINT32 length)
|
| +{
|
| + A_STATUS status = A_ERROR;
|
| + A_UINT32 lastWord = 0;
|
| + A_UINT32 lastWordOffset = length & ~0x3;
|
| + A_UINT32 unalignedBytes = length & 0x3;
|
| +
|
| + status = BMILZStreamStart (device, address);
|
| + if (A_FAILED(status)) {
|
| + return A_ERROR;
|
| + }
|
| +
|
| + if (unalignedBytes) {
|
| + /* copy the last word into a zero padded buffer */
|
| + A_MEMCPY(&lastWord, &buffer[lastWordOffset], unalignedBytes);
|
| + }
|
| +
|
| + status = BMILZData(device, buffer, lastWordOffset);
|
| +
|
| + if (A_FAILED(status)) {
|
| + return A_ERROR;
|
| + }
|
| +
|
| + if (unalignedBytes) {
|
| + status = BMILZData(device, (A_UINT8 *)&lastWord, 4);
|
| + }
|
| +
|
| + if (A_SUCCESS(status)) {
|
| + //
|
| + // Close compressed stream and open a new (fake) one. This serves mainly to flush Target caches.
|
| + //
|
| + status = BMILZStreamStart (device, 0x00);
|
| + if (A_FAILED(status)) {
|
| + return A_ERROR;
|
| + }
|
| + }
|
| + return status;
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIRawWrite(HIF_DEVICE *device, A_UCHAR *buffer, A_UINT32 length)
|
| +{
|
| + return bmiBufferSend(device, buffer, length);
|
| +}
|
| +
|
| +A_STATUS
|
| +BMIRawRead(HIF_DEVICE *device, A_UCHAR *buffer, A_UINT32 length, A_BOOL want_timeout)
|
| +{
|
| + return bmiBufferReceive(device, buffer, length, want_timeout);
|
| +}
|
|
|