예제 #1
0
/**
 *  @brief Transfers firmware to card
 *
 *  @param priv      A Pointer to bt_private structure
 *  @param fw        A Pointer to fw image
 *  @param fw_len    fw image len
 *  @return          BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no.
 */
static int
sd_init_fw_dpc(bt_private *priv, u8 *fw, int fw_len)
{
	struct sdio_mmc_card *card = (struct sdio_mmc_card *)priv->bt_dev.card;
	u8 *firmware = fw;
	int firmwarelen = fw_len;
	u8 base0;
	u8 base1;
	int ret = BT_STATUS_SUCCESS;
	int offset;
	void *tmpfwbuf = NULL;
	int tmpfwbufsz;
	u8 *fwbuf;
	u16 len;
	int txlen = 0;
	int tx_blocks = 0;
	int i = 0;
	int tries = 0;
	u8 sq_read_base_address_a0_reg = SQ_READ_BASE_ADDRESS_A0_REG;
	u8 sq_read_base_address_a1_reg = SQ_READ_BASE_ADDRESS_A1_REG;
	u8 crc_buffer = 0;
	u8 *header_crc_fw = NULL;
	u8 header_crc_fw_len = 0;

	header_crc_fw = fw_crc_header_rb_2;
	header_crc_fw_len = FW_CRC_HEADER_RB2;

	ENTER();

	PRINTM(INFO, "BT: Downloading FW image (%d bytes)\n", firmwarelen);

	tmpfwbufsz = BT_UPLD_SIZE + DMA_ALIGNMENT;
	tmpfwbuf = kzalloc(tmpfwbufsz, GFP_KERNEL);
	if (!tmpfwbuf) {
		PRINTM(ERROR,
		       "BT: Unable to allocate buffer for firmware. Terminating download\n");
		ret = BT_STATUS_FAILURE;
		goto done;
	}
	/* Ensure aligned firmware buffer */
	fwbuf = (u8 *)ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT);

	if (!(priv->fw_crc_check)
		) {
		/* CRC check not required, use custom header first */
		firmware = header_crc_fw;
		firmwarelen = header_crc_fw_len;
		crc_buffer = 1;
	}

	/* Perform firmware data transfer */
	offset = 0;
	do {
		/* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits
		 */
		ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
		if (ret < 0) {
			PRINTM(FATAL,
			       "BT: FW download with helper poll status timeout @ %d\n",
			       offset);
			goto done;
		}
		if (!crc_buffer)
			/* More data? */
			if (offset >= firmwarelen)
				break;

		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
			base0 = sdio_readb(card->func,
					   sq_read_base_address_a0_reg, &ret);
			if (ret) {
				PRINTM(WARN, "Dev BASE0 register read failed:"
				       " base0=0x%04X(%d). Terminating download\n",
				       base0, base0);
				ret = BT_STATUS_FAILURE;
				goto done;
			}
			base1 = sdio_readb(card->func,
					   sq_read_base_address_a1_reg, &ret);
			if (ret) {
				PRINTM(WARN, "Dev BASE1 register read failed:"
				       " base1=0x%04X(%d). Terminating download\n",
				       base1, base1);
				ret = BT_STATUS_FAILURE;
				goto done;
			}
			len = (((u16) base1) << 8) | base0;

			if (len != 0)
				break;
			udelay(10);
		}

		if (len == 0)
			break;
		else if (len > BT_UPLD_SIZE) {
			PRINTM(FATAL,
			       "BT: FW download failure @ %d, invalid length %d\n",
			       offset, len);
			ret = BT_STATUS_FAILURE;
			goto done;
		}

		txlen = len;

		if (len & BIT(0)) {
			i++;
			if (i > MAX_WRITE_IOMEM_RETRY) {
				PRINTM(FATAL,
				       "BT: FW download failure @ %d, over max retry count\n",
				       offset);
				ret = BT_STATUS_FAILURE;
				goto done;
			}
			PRINTM(ERROR,
			       "BT: FW CRC error indicated by the helper:"
			       " len = 0x%04X, txlen = %d\n", len, txlen);
			len &= ~BIT(0);

			PRINTM(ERROR, "BT: retry: %d, offset %d\n", i, offset);
			/* Setting this to 0 to resend from same offset */
			txlen = 0;
		} else {
			i = 0;

			/* Set blocksize to transfer - checking for last block */
			if (firmwarelen - offset < txlen)
				txlen = firmwarelen - offset;

			PRINTM(INFO, ".");

			tx_blocks =
				(txlen + SD_BLOCK_SIZE_FW_DL -
				 1) / SD_BLOCK_SIZE_FW_DL;

			/* Copy payload to buffer */
			memcpy(fwbuf, &firmware[offset], txlen);
		}

		/* Send data */
		ret = sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf,
				   tx_blocks * SD_BLOCK_SIZE_FW_DL);

		if (ret < 0) {
			PRINTM(ERROR,
			       "BT: FW download, write iomem (%d) failed @ %d\n",
			       i, offset);
			sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret);
			if (ret)
				PRINTM(ERROR, "write ioreg failed (CFG)\n");
		}

		offset += txlen;
		if (crc_buffer) {
			if (offset >= header_crc_fw_len) {
				/* Custom header download complete, restore
				   original FW */
				offset = 0;
				firmware = fw;
				firmwarelen = fw_len;
				crc_buffer = 0;
			}
		}
	} while (TRUE);

	PRINTM(MSG, "BT: FW download over, size %d bytes\n", offset);

	ret = BT_STATUS_SUCCESS;
done:
	kfree(tmpfwbuf);
	LEAVE();
	return ret;
}
예제 #2
0
/*----------------------------------------------------------------------------*/
BOOL
kalDevPortWrite (
    IN P_GLUE_INFO_T  prGlueInfo,
    IN UINT_16        u2Port,
    IN UINT_16        u2Len,
    IN PUINT_8        pucBuf,
    IN UINT_16        u2ValidInBufSize
)
{
    P_GL_HIF_INFO_T prHifInfo = NULL;
    PUINT_8 pucSrc = NULL;
    int count = u2Len;
    int ret = 0;
    int bNum = 0;

#if (MTK_WCN_HIF_SDIO == 0)
    struct sdio_func *prSdioFunc = NULL;
#endif

#if DBG
    //printk(KERN_INFO DRV_NAME"++kalDevPortWrite++ buf:0x%p, port:0x%x, length:%d\n", pucBuf, u2Port, u2Len);
#endif

    ASSERT(prGlueInfo);
    prHifInfo = &prGlueInfo->rHifInfo;

    ASSERT(pucBuf);
    pucSrc = pucBuf;

    ASSERT(u2Len <= u2ValidInBufSize);

#if (MTK_WCN_HIF_SDIO == 0)
    prSdioFunc = prHifInfo->func;
    ASSERT(prSdioFunc->cur_blksize > 0);

    if (!in_interrupt) {
        sdio_claim_host(prSdioFunc);
    }

    /* Split buffer into multiple single block to workaround hifsys */
    while (count >= prSdioFunc->cur_blksize) {
        count -= prSdioFunc->cur_blksize;
        bNum++;
    }
    if (count > 0 && bNum > 0) {
        bNum++;
    }

    if (bNum > 0) { // block mode
        ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, prSdioFunc->cur_blksize * bNum);

#ifdef CONFIG_X86
        /* ENE workaround */
        {
            int tmp;
            sdio_writel(prSdioFunc, 0x0, SDIO_X86_WORKAROUND_WRITE_MCR, &tmp);
        }
#endif

    }
    else {  // byte mode
        if(count & 0x3L) {
            int aligned_count = (count+3) & (~0x3L);
            ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, aligned_count);
        } else {
            ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, count);
        }
    }

    if (!in_interrupt) {
        sdio_release_host(prSdioFunc);
    }
#else
    /* Split buffer into multiple single block to workaround hifsys */
    while (count >= ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz)) {
        count -= ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz);
        bNum++;
    }
    if (count > 0 && bNum > 0) {
        bNum++;
    }

    if (bNum > 0) { // block mode
        ret = mtk_wcn_hif_sdio_write_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucSrc,
                                         ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz) * bNum);
    }
    else {  // byte mode
        ret = mtk_wcn_hif_sdio_write_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucSrc, count);
    }
#endif

    if (ret) {
        kalSendAeeWarning(HIF_SDIO_ERR_TITLE_STR, HIF_SDIO_ERR_DESC_STR "sdio_writesb() reports error: %x", ret);
        DBGLOG(HAL, ERROR, ("sdio_writesb() reports error: %x", ret));
    }

    return (ret) ? FALSE : TRUE;
} /* end of kalDevPortWrite() */
예제 #3
0
/**
 *  @brief This function sends data to the card.
 *
 *  @param priv    A pointer to bt_private structure
 *  @param payload A pointer to the data/cmd buffer
 *  @param nb      Length of data/cmd
 *  @return        BT_STATUS_SUCCESS or BT_STATUS_FAILURE
 */
int
sbi_host_to_card(bt_private *priv, u8 *payload, u16 nb)
{
	struct sdio_mmc_card *card = priv->bt_dev.card;
	struct m_dev *m_dev = &(priv->bt_dev.m_dev[BT_SEQ]);
	int ret = BT_STATUS_SUCCESS;
	int buf_block_len;
	int blksz;
	int i = 0;
	u8 *buf = NULL;
	void *tmpbuf = NULL;
	int tmpbufsz;

	ENTER();

	if (!card || !card->func) {
		PRINTM(ERROR, "BT: card or function is NULL!\n");
		LEAVE();
		return BT_STATUS_FAILURE;
	}
	buf = payload;

	blksz = SD_BLOCK_SIZE;
	buf_block_len = (nb + blksz - 1) / blksz;
	/* Allocate buffer and copy payload */
	if ((t_ptr)payload & (DMA_ALIGNMENT - 1)) {
		tmpbufsz = buf_block_len * blksz + DMA_ALIGNMENT;
		tmpbuf = kzalloc(tmpbufsz, GFP_KERNEL);
		if (!tmpbuf) {
			LEAVE();
			return BT_STATUS_FAILURE;
		}
		/* Ensure 8-byte aligned CMD buffer */
		buf = (u8 *)ALIGN_ADDR(tmpbuf, DMA_ALIGNMENT);
		memcpy(buf, payload, nb);
	}
	sdio_claim_host(card->func);
#define MAX_WRITE_IOMEM_RETRY	2
	do {
		/* Transfer data to card */
		ret = sdio_writesb(card->func, priv->bt_dev.ioport, buf,
				   buf_block_len * blksz);
		if (ret < 0) {
			i++;
			PRINTM(ERROR,
			       "BT: host_to_card, write iomem (%d) failed: %d\n",
			       i, ret);
			sdio_writeb(card->func, HOST_WO_CMD53_FINISH_HOST,
				    CONFIGURATION_REG, &ret);
			udelay(20);
			ret = BT_STATUS_FAILURE;
			if (i > MAX_WRITE_IOMEM_RETRY)
				goto exit;
		} else {
			PRINTM(DATA, "BT: SDIO Blk Wr %s: len=%d\n",
			       m_dev->name, nb);
			DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Wr", payload, nb);
		}
	} while (ret == BT_STATUS_FAILURE);
	priv->bt_dev.tx_dnld_rdy = FALSE;
exit:
	sdio_release_host(card->func);
	kfree(tmpbuf);
	LEAVE();
	return ret;
}
예제 #4
0
파일: hif.c 프로젝트: DerArtem/AR6kSDK.3.0
static A_STATUS
__HIFReadWrite(HIF_DEVICE *device,
             A_UINT32 address,
             A_UCHAR *buffer,
             A_UINT32 length,
             A_UINT32 request,
             void *context)
{
    A_UINT8 opcode;
    A_STATUS    status = A_OK;
    int     ret;
    A_UINT8 *tbuffer;
    A_BOOL   bounced = FALSE;

    AR_DEBUG_ASSERT(device != NULL);
    AR_DEBUG_ASSERT(device->func != NULL);

    AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: 0x%p, buffer:0x%p (addr:0x%X)\n", 
                    device, buffer, address));

    do {
        if (request & HIF_EXTENDED_IO) {
            /*AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Command type: CMD53\n")); */
        } else {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
                            ("AR6000: Invalid command type: 0x%08x\n", request));
            status = A_EINVAL;
            break;
        }

        if (request & HIF_BLOCK_BASIS) {
            /* round to whole block length size */
            length = (length / HIF_MBOX_BLOCK_SIZE) * HIF_MBOX_BLOCK_SIZE;
            AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
                            ("AR6000: Block mode (BlockLen: %d)\n",
                            length));
        } else if (request & HIF_BYTE_BASIS) {
            AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
                            ("AR6000: Byte mode (BlockLen: %d)\n",
                            length));
        } else {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
                            ("AR6000: Invalid data mode: 0x%08x\n", request));
            status = A_EINVAL;
            break;
        }

#if 0
        /* useful for checking register accesses */
        if (length & 0x3) {
            A_PRINTF(KERN_ALERT"AR6000: HIF (%s) is not a multiple of 4 bytes, addr:0x%X, len:%d\n",
                                request & HIF_WRITE ? "write":"read", address, length);
        }
#endif

        if (request & HIF_WRITE) {
            if ((address >= HIF_MBOX_START_ADDR(0)) &&
                (address <= HIF_MBOX_END_ADDR(3)))
            {
    
                AR_DEBUG_ASSERT(length <= HIF_MBOX_WIDTH);
    
                /*
                 * Mailbox write. Adjust the address so that the last byte
                 * falls on the EOM address.
                 */
                address += (HIF_MBOX_WIDTH - length);
            }
        }

        if (request & HIF_FIXED_ADDRESS) {
            opcode = CMD53_FIXED_ADDRESS;
            AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Fixed 0x%X\n", address));
        } else if (request & HIF_INCREMENTAL_ADDRESS) {
            opcode = CMD53_INCR_ADDRESS;
            AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Incremental 0x%X\n", address));
        } else {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
                            ("AR6000: Invalid address mode: 0x%08x\n", request));
            status = A_EINVAL;
            break;
        }

        if (request & HIF_WRITE) {
#if HIF_USE_DMA_BOUNCE_BUFFER
            if (BUFFER_NEEDS_BOUNCE(buffer)) {
                AR_DEBUG_ASSERT(device->dma_buffer != NULL);
                tbuffer = device->dma_buffer;
                    /* copy the write data to the dma buffer */
                AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
                memcpy(tbuffer, buffer, length);
                bounced = TRUE;
            } else {
                tbuffer = buffer;    
            }
#else
	        tbuffer = buffer;
#endif
            if (opcode == CMD53_FIXED_ADDRESS) {
                ret = sdio_writesb(device->func, address, tbuffer, length);
                AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writesb ret=%d address: 0x%X, len: %d, 0x%X\n",
						  ret, address, length, *(int *)tbuffer));
            } else {
                ret = sdio_memcpy_toio(device->func, address, tbuffer, length);
                AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writeio ret=%d address: 0x%X, len: %d, 0x%X\n",
						  ret, address, length, *(int *)tbuffer));
            }
        } else if (request & HIF_READ) {
#if HIF_USE_DMA_BOUNCE_BUFFER
            if (BUFFER_NEEDS_BOUNCE(buffer)) {
                AR_DEBUG_ASSERT(device->dma_buffer != NULL);
                AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE);
                tbuffer = device->dma_buffer;
                bounced = TRUE;
            } else {
                tbuffer = buffer;    
            }
#else
            tbuffer = buffer;
#endif
            if (opcode == CMD53_FIXED_ADDRESS) {
                ret = sdio_readsb(device->func, tbuffer, address, length);
                AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readsb ret=%d address: 0x%X, len: %d, 0x%X\n",
						  ret, address, length, *(int *)tbuffer));
            } else {
                ret = sdio_memcpy_fromio(device->func, tbuffer, address, length);
                AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readio ret=%d address: 0x%X, len: %d, 0x%X\n",
						  ret, address, length, *(int *)tbuffer));
            }
#if HIF_USE_DMA_BOUNCE_BUFFER
            if (bounced) {
    	           /* copy the read data from the dma buffer */
                memcpy(buffer, tbuffer, length);
            }
#endif
        } else {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
                            ("AR6000: Invalid direction: 0x%08x\n", request));
            status = A_EINVAL;
            break;
        }

        if (ret) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
                            ("AR6000: SDIO bus operation failed! MMC stack returned : %d \n", ret));
            status = A_ERROR;
        }
    } while (FALSE);

    return status;
}
예제 #5
0
int sif_io_sync(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag)
{
        int err = 0;
        u8 * ibuf = NULL;
        bool need_ibuf = false;
        struct esp_sdio_ctrl *sctrl = NULL;
        struct sdio_func *func = NULL;

	if (epub == NULL || buf == NULL) {
        	ESSERT(0);
		err = -EINVAL;
		goto _exit;
	}

        sctrl = (struct esp_sdio_ctrl *)epub->sif;
        func = sctrl->func;
	if (func == NULL) {
		ESSERT(0);	
		err = -EINVAL;
		goto _exit;
	}

        if (bad_buf(buf)) {
                esp_dbg(ESP_DBG_TRACE, "%s dst 0x%08x, len %d badbuf\n", __func__, addr, len);
                need_ibuf = true;
                ibuf = sctrl->dma_buffer;
        } else {
                ibuf = buf;
        }

        if (flag & SIF_BLOCK_BASIS) {
                /* round up for block data transcation */
        }

        if (flag & SIF_TO_DEVICE) {

                esp_dbg(ESP_DBG_TRACE, "%s to addr 0x%08x, len %d \n", __func__, addr, len);
                if (need_ibuf)
                        memcpy(ibuf, buf, len);

                sdio_claim_host(func);

                if (flag & SIF_FIXED_ADDR)
                        err = sdio_writesb(func, addr, ibuf, len);
                else if (flag & SIF_INC_ADDR) {
                        err = sdio_memcpy_toio(func, addr, ibuf, len);
                }
                sif_platform_check_r1_ready(epub);
                sdio_release_host(func);
        } else if (flag & SIF_FROM_DEVICE) {

                esp_dbg(ESP_DBG_TRACE, "%s from addr 0x%08x, len %d \n", __func__, addr, len);

                sdio_claim_host(func);

                if (flag & SIF_FIXED_ADDR)
                        err = sdio_readsb(func, ibuf, addr, len);
                else if (flag & SIF_INC_ADDR) {
                        err = sdio_memcpy_fromio(func, ibuf, addr, len);
                }

                sdio_release_host(func);

                if (!err && need_ibuf)
                        memcpy(buf, ibuf, len);
        }

_exit:
        return err;
}
예제 #6
0
/**
 *  @brief This function downloads firmware image to the card.
 *
 *  @param priv    	A pointer to bt_private structure
 *  @return 	   	BT_STATUS_SUCCESS or BT_STATUS_FAILURE
 */
int
sd_download_firmware_w_helper(bt_private * priv)
{
    struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
    const struct firmware *fw_firmware = NULL;
    u8 *firmware = NULL;
    int firmwarelen;
    u8 base0;
    u8 base1;
    int ret = BT_STATUS_SUCCESS;
    int offset;
    void *tmpfwbuf = NULL;
    int tmpfwbufsz;
    u8 *fwbuf;
    u16 len;
    int txlen = 0;
    int tx_blocks = 0;
    int i = 0;
    int tries = 0;
#ifdef FW_DOWNLOAD_SPEED
    u32 tv1, tv2;
#endif
    char *cur_fw_name = NULL;

    ENTER();

    if (fw_name == NULL)
        /* Check revision ID */
        switch (priv->adapter->chip_rev) {
        case SD8787_W0:
        case SD8787_W1:
            cur_fw_name = SD8787_W1_FW_NAME;
            break;
        case SD8787_A0:
        case SD8787_A1:
            cur_fw_name = SD8787_AX_FW_NAME;
            break;
        default:
            cur_fw_name = DEFAULT_FW_NAME;
            break;
        }
    else
        cur_fw_name = fw_name;
    if ((ret =
                request_firmware(&fw_firmware, cur_fw_name,
                                 priv->hotplug_device)) < 0) {
        PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret);
        goto done;
    }

    if (fw_firmware) {
        firmware = (u8 *) fw_firmware->data;
        firmwarelen = fw_firmware->size;
    } else {
        PRINTM(MSG, "No firmware image found! Terminating download\n");
        ret = BT_STATUS_FAILURE;
        goto done;
    }

    PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen);

#ifdef FW_DOWNLOAD_SPEED
    tv1 = get_utimeofday();
#endif

#ifdef PXA3XX_DMA_ALIGN
    tmpfwbufsz = ALIGN_SZ(BT_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT);
#else /* PXA3XX_DMA_ALIGN */
    tmpfwbufsz = BT_UPLD_SIZE;
#endif
    tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);
    if (!tmpfwbuf) {
        PRINTM(ERROR,
               "Unable to allocate buffer for firmware. Terminating download\n");
        ret = BT_STATUS_FAILURE;
        goto done;
    }
    memset(tmpfwbuf, 0, tmpfwbufsz);
#ifdef PXA3XX_DMA_ALIGN
    /* Ensure 8-byte aligned firmware buffer */
    fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, PXA3XX_DMA_ALIGNMENT);
#else /* PXA3XX_DMA_ALIGN */
    fwbuf = (u8 *) tmpfwbuf;
#endif

    /* Perform firmware data transfer */
    offset = 0;
    do {
        /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */
        ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY);
        if (ret < 0) {
            PRINTM(FATAL, "FW download with helper poll status timeout @ %d\n",
                   offset);
            goto done;
        }

        /* More data? */
        if (offset >= firmwarelen)
            break;

        for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
            base0 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A0_REG, &ret);
            if (ret) {
                PRINTM(WARN, "Dev BASE0 register read failed:"
                       " base0=0x%04X(%d). Terminating download\n", base0,
                       base0);
                ret = BT_STATUS_FAILURE;
                goto done;
            }
            base1 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A1_REG, &ret);
            if (ret) {
                PRINTM(WARN, "Dev BASE1 register read failed:"
                       " base1=0x%04X(%d). Terminating download\n", base1,
                       base1);
                ret = BT_STATUS_FAILURE;
                goto done;
            }
            len = (((u16) base1) << 8) | base0;

            if (len != 0)
                break;
            udelay(10);
        }

        if (len == 0)
            break;
        else if (len > BT_UPLD_SIZE) {
            PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n",
                   offset, len);
            ret = BT_STATUS_FAILURE;
            goto done;
        }

        txlen = len;

        if (len & BIT(0)) {
            i++;
            if (i > MAX_WRITE_IOMEM_RETRY) {
                PRINTM(FATAL,
                       "FW download failure @ %d, over max retry count\n",
                       offset);
                ret = BT_STATUS_FAILURE;
                goto done;
            }
            PRINTM(ERROR, "FW CRC error indicated by the helper:"
                   " len = 0x%04X, txlen = %d\n", len, txlen);
            len &= ~BIT(0);
            /* Setting this to 0 to resend from same offset */
            txlen = 0;
        } else {
            i = 0;

            /* Set blocksize to transfer - checking for last block */
            if (firmwarelen - offset < txlen)
                txlen = firmwarelen - offset;

            PRINTM(INFO, ".");

            tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL;

            /* Copy payload to buffer */
            memcpy(fwbuf, &firmware[offset], txlen);
        }

        /* Send data */
        ret =
            sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf,
                         tx_blocks * SD_BLOCK_SIZE_FW_DL);

        if (ret < 0) {
            PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i,
                   offset);
            sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret);
            if (ret)
                PRINTM(ERROR, "write ioreg failed (CFG)\n");
        }

        offset += txlen;
    } while (TRUE);

    PRINTM(INFO, "\nFW download over, size %d bytes\n", offset);

    ret = BT_STATUS_SUCCESS;
done:
#ifdef FW_DOWNLOAD_SPEED
    tv2 = get_utimeofday();
    PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000,
           (tv1 % 1000000) / 1000, tv1 % 1000);
    PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000,
           (tv2 % 1000000) / 1000, tv2 % 1000);
    tv2 -= tv1;
    PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000,
           (tv2 % 1000000) / 1000, tv2 % 1000);
#endif
    if (tmpfwbuf)
        kfree(tmpfwbuf);
    if (fw_firmware)
        release_firmware(fw_firmware);

    LEAVE();
    return ret;
}
예제 #7
0
파일: wlan.c 프로젝트: Anon0/openiBoot
int wlan_prog_helper(const uint8_t * firmware, int size)
{
	int ret;
	uint8_t status;
	uint8_t *chunk_buffer;
	uint32_t chunk_size;
	uint64_t startTime;

	bufferPrintf("wlan: programming firmware helper...\r\n");

	chunk_buffer = (uint8_t*) memalign(64, 4);
	if (!chunk_buffer) {
		ret = -1;
		goto release_fw;
	}

	ret = sdio_set_block_size(1, 32);
	if (ret)
		goto release;

	while (size) {
		startTime = timer_get_system_microtime();
		while (TRUE) {
			status = sdio_readb(1, IF_SDIO_STATUS, &ret);
			if (ret)
				goto release;

			if ((status & IF_SDIO_IO_RDY) &&
					(status & IF_SDIO_DL_RDY))
				break;

			if(has_elapsed(startTime, 1000 * 1000)) {
				ret = -1;
				goto release;
			}

			udelay(1000);
		}

		if(size > 60)
			chunk_size = 60;
		else
			chunk_size = size;


		*((uint32_t*)chunk_buffer) = chunk_size;
		memcpy(chunk_buffer + 4, firmware, chunk_size);

		//bufferPrintf("wlan: sending %d bytes chunk\r\n", chunk_size);
		
		ret = sdio_writesb(1, ioport,
				chunk_buffer, 64);
		if (ret)
			goto release;

		firmware += chunk_size;
		size -= chunk_size;
	}

	/* an empty block marks the end of the transfer */
	memset(chunk_buffer, 0, 4);
	ret = sdio_writesb(1, ioport, chunk_buffer, 64);
	if (ret)
		goto release;

	bufferPrintf("wlan: waiting for helper to boot\r\n");

	/* wait for the helper to boot by looking at the size register */
	startTime = timer_get_system_microtime();
	while (TRUE) {
		uint16_t req_size;

		req_size = sdio_readb(1, IF_SDIO_RD_BASE, &ret);
		if (ret)
			goto release;

		req_size |= sdio_readb(1, IF_SDIO_RD_BASE + 1, &ret) << 8;
		if (ret)
			goto release;

		if (req_size != 0)
			break;

		if(has_elapsed(startTime, 1000 * 1000)) {
			ret = -1;
			goto release;
		}

		udelay(10000);
	}

	ret = 0;
	bufferPrintf("wlan: helper has booted!\r\n");

release:
	free(chunk_buffer);

release_fw:

	if (ret)
		bufferPrintf("wlan: failed to load helper firmware\r\n");

	return ret;
}
예제 #8
0
파일: wlan.c 프로젝트: Anon0/openiBoot
int wlan_prog_real(const uint8_t* firmware, size_t size)
{
	int ret;
	uint8_t status;
	uint8_t *chunk_buffer;
	uint32_t chunk_size;
	size_t req_size;
	uint64_t startTime;

	bufferPrintf("wlan: programming firmware...\r\n");

	chunk_buffer = (uint8_t*) memalign(512, 4);
	if (!chunk_buffer) {
		ret = -1;
		goto release_fw;
	}
	
	ret = sdio_set_block_size(1, 32);
	if (ret)
		goto release;

	while (size) {
		startTime = timer_get_system_microtime();
		while (1) {
			status = sdio_readb(1, IF_SDIO_STATUS, &ret);
			if (ret)
				goto release;
			if ((status & IF_SDIO_IO_RDY) &&
					(status & IF_SDIO_DL_RDY))
				break;
			if(has_elapsed(startTime, 1000 * 1000)) {
				ret = -1;
				goto release;
			}
			udelay(1000);
		}

		req_size = sdio_readb(1, IF_SDIO_RD_BASE, &ret);
		if (ret)
			goto release;

		req_size |= sdio_readb(1, IF_SDIO_RD_BASE + 1, &ret) << 8;
		if (ret)
			goto release;

		//bufferPrintf("wlan: firmware helper wants %d bytes\r\n", (int)req_size);

		if (req_size == 0) {
			bufferPrintf("wlan: firmware helper gave up early\r\n");
			ret = -1;
			goto release;
		}

		if (req_size & 0x01) {
			bufferPrintf("wlan: firmware helper signalled error\r\n");
			ret = -1;
			goto release;
		}

		if (req_size > size)
			req_size = size;

		while (req_size) {
			if(req_size > 512)
				chunk_size = 512;
			else
				chunk_size = req_size;

			memcpy(chunk_buffer, firmware, chunk_size);

			//bufferPrintf("wlan: sending %d bytes (%d bytes) chunk\r\n",
			//   chunk_size, (chunk_size + 31) / 32 * 32);

			int to_send;
			to_send = chunk_size / 32;
			to_send *= 32;

			if(to_send < chunk_size)
				to_send += 32;

			ret = sdio_writesb(1, ioport,
					chunk_buffer, to_send);
			if (ret)
				goto release;

			firmware += chunk_size;
			size -= chunk_size;
			req_size -= chunk_size;
		}
	}

	ret = 0;

	bufferPrintf("wlan: waiting for firmware to boot\r\n");

	/* wait for the firmware to boot */
	startTime = timer_get_system_microtime();
	while (TRUE) {
		uint16_t scratch;

		scratch = wlan_read_scratch(&ret);
		if (ret)
			goto release;

		if (scratch == IF_SDIO_FIRMWARE_OK)
			break;

		if(has_elapsed(startTime, 1000 * 1000)) {
			ret = -1;
			goto release;
		}

		udelay(10000);
	}

	ret = 0;

	bufferPrintf("wlan: firmware booted!\r\n");

release:
	free(chunk_buffer);

release_fw:

	if (ret)
		bufferPrintf("wlan: failed to load firmware\r\n");

	return ret;
}