Ejemplo n.º 1
0
/**
 * \brief   This function sends the write command to MMCSD card.
 *
 * \param    mmcsdCtrlInfo It holds the mmcsd control information.
 * \param    ptr           It determines the address from where data has to written
 * \param    block         It determines to which block data to be written
 * \param    nblks         It determines the number of blocks to be written
 *
 * \returns  1 - successfull written of data.
 *           0 - failure to write the data.
 **/
unsigned int MMCSDWriteCmdSend(mmcsdCtrlInfo *ctrl, void *ptr, unsigned int block,
                               unsigned int nblks)
{
    mmcsdCardInfo *card = ctrl->card;
    unsigned int status = 0;
    unsigned int address;
    mmcsdCmd cmd;

    /*
     * Address is in blks for high cap cards and in actual bytes
     * for standard capacity cards
     */

    if (card->highCap)
    {
        address = block;
    }
    else
    {
        address = block * card->blkLen;
    }
#ifdef CACHE
    /* Clean the data cache. */
    CacheDataCleanBuff((unsigned int) ptr, (512 * nblks));
#endif
    ctrl->xferSetup(ctrl, 0, ptr, 512, nblks);

    cmd.flags = SD_CMDRSP_WRITE | SD_CMDRSP_DATA | (ctrl->dmaEnable << SD_CMDRSP_DMAEN_OFFSET);
    cmd.arg = address;
    cmd.nblks = nblks;

    if (nblks > 1)
    {
        cmd.idx = SD_CMD(25);
    }
    else
    {
        cmd.idx = SD_CMD(24);
    }


    status = ctrl->cmdSend(ctrl, &cmd);

    if (status == 0)
    {
        return 0;
    }

    status = ctrl->xferStatusGet(ctrl);

    if (status == 0)
    {
        return 0;
    }

    while (!MMCSDWaitCardReadyForData(ctrl));

    return 1;
}
Ejemplo n.º 2
0
/**
 * \brief   Configure the MMC/SD bus width
 *
 * \param    mmcsdCtrlInfo It holds the mmcsd control information.
 *
 * \param   buswidth   SD/MMC bus width.\n
 *
 *  buswidth can take the values.\n
 *     HS_MMCSD_BUS_WIDTH_4BIT.\n
 *     HS_MMCSD_BUS_WIDTH_1BIT.\n
 *
 * \return  None.
 *
 **/
unsigned int MMCSDBusWidthSet(mmcsdCtrlInfo *ctrl)
{
    mmcsdCardInfo *card = ctrl->card;
    unsigned int status = 0;
    mmcsdCmd capp;

    if (card->cardType == MMCSD_CARD_MMC)
    {//на проверку шины положили потому что не получается нифига эта проверка)
    	//а не сделать ли нам все по спецификации и не через анус? - не сделать)
		//если надо 4 бита
    	if (card->sd_ver < 4)
    	{
    		UARTPuts("Card restricted to 1-wire wide bus mode.\n", -1);
    		return 1; //какие мы молодцы!
    	}
		if (card->busWidth & SD_BUS_WIDTH_4BIT)
		{
			if (ctrl->busWidth & SD_BUS_WIDTH_4BIT)
			{
				//тест шины 4 бита - забили на него
				ctrl->busWidthConfig(ctrl, SD_BUS_WIDTH_4BIT);
				capp.idx = SD_CMD(6);
				capp.flags = SD_CMDRSP_BUSY;
				capp.arg = 0x03B70100;
				status = ctrl->cmdSend(ctrl, &capp);
				if (status == 0)  return 0;
				//аццки важный фикс!! без этого вылетает!
				//ждем пока карта не снимет busy!
		        while (!(HWREG(ctrl->memBase + MMCHS_PSTATE) & (unsigned int)BIT(20)));
			}
		}
		else if (card->busWidth & SD_BUS_WIDTH_8BIT) //хотим 8 бит
		{
			if (ctrl->busWidth & SD_BUS_WIDTH_8BIT)
			{
				//тест шины 8 бит - забили на него
				ctrl->busWidthConfig(ctrl, SD_BUS_WIDTH_8BIT);
				capp.idx = SD_CMD(6);
				capp.flags = SD_CMDRSP_BUSY;
				capp.arg = 0x03B70200;
				status = ctrl->cmdSend(ctrl, &capp);
				if (status == 0)  return 0;
				//аццки важный фикс!! без этого вылетает!
				//ждем пока карта не снимет busy!
		        while (!(HWREG(ctrl->memBase + MMCHS_PSTATE) & (unsigned int)BIT(20)));

			}
		}



	}
    else
    {
    	return 0;
    }

    return 1; //какие мы молодцы!
}
Ejemplo n.º 3
0
/**
 * \brief   This function sends the write command to MMCSD card.
 *
 * \param    mmcsdCtrlInfo It holds the mmcsd control information.
 * \param    ptr           It determines the address to where data has to read
 * \param    block         It determines from which block data to be read
 * \param    nblks         It determines the number of blocks to be read
 *
 * \returns  1 - successfull reading of data.
 *           0 - failure to the data.
 **/
unsigned int MMCSDReadCmdSend(mmcsdCtrlInfo *ctrl, void *ptr, unsigned int block,
                              unsigned int nblks)
{
    mmcsdCardInfo *card = ctrl->card;
    unsigned int status = 0;
    unsigned int address;
    mmcsdCmd cmd;

    /*
     * Address is in blks for high cap cards and in actual bytes
     * for standard capacity cards
     */
    if (card->highCap)
    {
        address = block;
    }
    else
    {
        address = block * card->blkLen;
    }

    ctrl->xferSetup(ctrl, 1, ptr, 512, nblks);

    cmd.flags = SD_CMDRSP_READ | SD_CMDRSP_DATA | (ctrl->dmaEnable << SD_CMDRSP_DMAEN_OFFSET);
    cmd.arg = address;
    cmd.nblks = nblks;

    if (nblks > 1)
    {
        cmd.idx = SD_CMD(18);
    }
    else
    {
        cmd.idx = SD_CMD(17);
    }

    status = ctrl->cmdSend(ctrl, &cmd);
    if (status == 0)
    {
        return 0;
    }

    status = ctrl->xferStatusGet(ctrl);

    if (status == 0)
    {
        return 0;
    }
#ifdef CACHE
    /* Invalidate the data cache. */
    CacheDataInvalidateBuff((unsigned int)(ptr), 512 * nblks);
#endif
    return 1;
}
Ejemplo n.º 4
0
/**
 * @brief send sd command.
 *
 * The clock must be less than 400khz when the sd controller in identification mode.
 * @author Huang Xin
 * @date 2010-07-14
 * @param cmd_index[in] The command index.
 * @param rsp[in] The command response:no response ,short reponse or long response
 * @param arg[in] The cmd argument.
 * @return T_BOOL
 * @retval AK_TRUE: CMD sent successfully
 * @retval AK_FALSE: CMD sent failed

 */
T_BOOL send_cmd(T_U8 cmd_index, T_U8 resp, T_U32 arg)
{
    T_U32 cmd_value = 0;
    T_U32 status;

    if (cmd_index == SD_CMD(1) || cmd_index == SD_CMD(41) || cmd_index == SD_CMD(5))      //R3 is no crc
    {
        cmd_value = CPSM_ENABLE | ( resp << WAIT_REP_OFFSET) 
                                | ( cmd_index << CMD_INDEX_OFFSET) | RSP_CRC_NO_CHK;
    }
    else
    {
        cmd_value = CPSM_ENABLE | ( resp << WAIT_REP_OFFSET ) 
                                | ( cmd_index << CMD_INDEX_OFFSET) ;
    }

    REG32(s_SdReg_Base + oSD_ARG) = arg;
    REG32(s_SdReg_Base + oSD_CMD) = cmd_value;

    if (SD_NO_RESPONSE == resp)
    {
        while(1)
        {
            status = REG32(s_SdReg_Base + oSD_INT_STA);
            if (status & CMD_SENT)
            {
                return AK_TRUE;
            }
        }
    }
    else if ((SD_SHORT_RESPONSE == resp) ||(SD_LONG_RESPONSE == resp))
    {
        while(1)
        {
            status = REG32(s_SdReg_Base + oSD_INT_STA);
            if ((status & CMD_TIME_OUT)||(status & CMD_CRC_FAIL))
            {
                drv_print("ce, ", (cmd_index << 16) | status, AK_TRUE);
                return AK_FALSE;
            }
            else if (status & CMD_RESP_END)
            {
                return AK_TRUE;
            }
        }
    }
    else
    {
        return AK_FALSE;
    }
}
Ejemplo n.º 5
0
/**
 * \brief    This function configures the transmission speed in MMCSD.
 *
 * \param    mmcsdCtrlInfo It holds the mmcsd control information.
 *
 * \returns  1 - successfull.
 *           0 - failed.
 **/
unsigned int MMCSDTranSpeedSet(mmcsdCtrlInfo *ctrl)
{
    mmcsdCardInfo *card = ctrl->card;
    int status;
    mmcsdCmd cmd;


    if (card->cardType == MMCSD_CARD_MMC)
    {
    	//при инициализации eMMC уже была выставлена максимальная частота
    	//на которую может быть настроена карта без HS_TIMING по TRAN_SPEED из CSD
    	//теперь если highspeed = 1 делаем 48 МГц
    	if (card->sd_ver < 4) return 1; //карта уже на макс скорости
    	cmd.idx = SD_CMD(6);
    	cmd.flags = SD_CMDRSP_BUSY;
    	//взято из спецификации eMMC
    	cmd.arg = 0x03B90100;
		status = ctrl->cmdSend(ctrl, &cmd);
		if (status == 0)  return 0;

        status = ctrl->busFreqConfig(ctrl, 48000000);
        if (status != 0) return 0;
        ctrl->opClk = 48000000;
        //тут проблемка, не сразу после выхода из этой функции карта готова
        //нужна задержка какая-то
        //наерно если подождать пока DAT0 не поднимется в '1' будет норм
        while (!(HWREG(ctrl->memBase + MMCHS_PSTATE) & (unsigned int)BIT(20)));
    }
    else
    {
    	return 0;
    }

    return 1;
}
Ejemplo n.º 6
0
/**
 * \brief   This function resets the MMCSD card.
 *
 * \param    mmcsdCtrlInfo It holds the mmcsd control information.
 *
 * \returns  1 - successfull reset of card.
 *           0 - fails to reset the card.
 **/
unsigned int MMCSDCardReset(mmcsdCtrlInfo *ctrl)
{
    unsigned int status = 0;
    mmcsdCmd cmd;

    cmd.idx = SD_CMD(0);

    cmd.flags = SD_CMDRSP_NONE;
    cmd.arg = 0;

    status = ctrl->cmdSend(ctrl, &cmd);

    return status;
}
Ejemplo n.º 7
0
//Будем ждать готовности карты в течение времени таймаута и возвращать 1 в случае успеха
//Функция добавлена КП Дорошенко для фикса глюка карты, когда после инициализации или записи
//карта не сразу готова к новым подвигам
unsigned int MMCSDWaitCardReadyForData(mmcsdCtrlInfo *ctrl)
{
    mmcsdCardInfo *card = ctrl->card;
    unsigned int status = 0;
    mmcsdCmd cmd;
    unsigned int retry = 0xffffffff;

    cmd.idx = SD_CMD(13);
    cmd.flags = 0;
    cmd.arg = card->rca << 16;

	do{
		status = ctrl->cmdSend(ctrl, &cmd);
		if (status == 0) return status; //если нет ответа, можно выходить

	} while (!(cmd.rsp[0] & ((unsigned int)BIT(8))) && --retry); //кол-во попыток вышло, либо стоит бит READY_FOR_DATA

	if (0 == retry) return 0;

	return 1;
}
Ejemplo n.º 8
0
/**
 * Write block(s) from MMC/SD card. The implementation follows
 * '26.3.5 MMC/SD Mode Single-Block Read Operation Using EDMA' in 'spruh82a'.
 * @param  mmcsdCtrlInfo It holds the mmcsd control information.
 * @param  ptr           It determines the address from where data has to written
 * @param  block         It determines to which block data to be written (block >= 0)
 * @param  nblks         It determines the number of blocks to be written (nblks >= 1)
 * @retval 1             success
 * @retval 0             fail
 */
unsigned int
MMCSDWriteCmdSend(mmcsdCtrlInfo *ctrl, void *ptr, unsigned int block, unsigned int nblks) {
	// TODO: workaround for buggy WRITE_MULTI_BLOCK
	if (nblks > 1) {
		for (unsigned int i = 0; i < nblks; ++i) {
			unsigned int res = MMCSDWriteCmdSend(ctrl, ptr + i * MMCSD_MAX_BLOCK_LEN, block + i, 1);
			assert(res == 1);
		}
		return 1;
	}
	assert(nblks == 1);

	unsigned int status = 1; // 1 for success
	volatile struct st_mmcsd *mmc = ctrl->memBase;
	ER ercd;

	/* 1. Write the card's relative address to the MMC argument registers (MMCARGH and MMCARGL). */
	mmcsdCardInfo *card = ctrl->card;
	unsigned int address;
	/*
	 * TODO: check this -- ertl-liyixiao
	 * Address is in blks for high cap cards and in actual bytes
	 * for standard capacity cards
	 */
	assert(card->highCap);
	if (card->highCap)
		address = block;
	else
		address = block * card->blkLen;
	mmc->MMCARGHL = address;

	/* 2. Read card CSD to determine the card's maximum block length. */
	// TODO:
//	syslog(LOG_ERROR, "card->raw_csd[0]: 0x%08x", card->raw_csd[0]);
//	syslog(LOG_ERROR, "card->raw_csd[1]: 0x%08x", card->raw_csd[1]);
//	syslog(LOG_ERROR, "card->raw_csd[2]: 0x%08x", card->raw_csd[2]);
//	syslog(LOG_ERROR, "card->raw_csd[3]: 0x%08x", card->raw_csd[3]);
	syslog(LOG_ERROR, "MMCCTL: 0x%08x", mmc->MMCCTL);


	/* 3. Use the MMC command register (MMCCMD) to send the SET_BLOCKLEN command (if the block
	 length is different than the length used in the previous operation). The block length must be a multiple
	 of 512 bytes and less then the maximum block length specified in the CSD. */
	syslog(LOG_ERROR, "MMCCTL: 0x%08x", mmc->MMCCTL);
	syslog(LOG_ERROR, "MMCCLK: 0x%08x", mmc->MMCBLEN);
	// TODO:

	/* 4. Reset the FIFO (FIFORST bit in MMCFIFOCTL). */
	mmc->MMCFIFOCTL |= MMCSD_MMCFIFOCTL_FIFORST;
	mmc->MMCFIFOCTL &= ~MMCSD_MMCFIFOCTL_FIFORST;

	/* 5. Set the FIFO direction to send (FIFODIR bit in MMCFIFOCTL). */
	mmc->MMCFIFOCTL |= MMCSD_MMCFIFOCTL_FIFODIR;

	/* 6. Set the access width (ACCWD bits in MMCFIFOCTL). */
	mmc->MMCFIFOCTL &= ~MMCSD_MMCFIFOCTL_ACCWD;
	mmc->MMCFIFOCTL |= (MMCSD_MMCFIFOCTL_ACCWD_4BYTES << MMCSD_MMCFIFOCTL_ACCWD_SHIFT); // => 4 bytes

	/* 7. Set the FIFO threshold (FIFOLEV bit in MMCFIFOCTL). */
	mmc->MMCFIFOCTL |=  MMCSD_MMCFIFOCTL_FIFOLEV; // => 64 bytes

	/* 8. Set up DMA (DMA size needs to be greater than or equal to FIFOLEV setting). */
	CacheDataCleanBuff((unsigned int) ptr, (MMCSD_MAX_BLOCK_LEN * nblks)); // Clean data buffer to send
	arm926_drain_write_buffer(); // Memory barrier for data buffer to send
	ctrl->xferSetup(ctrl, 0, ptr, MMCSD_MAX_BLOCK_LEN, nblks);
	{
		syslog(LOG_ERROR, "origSrcAddr: 0x%08x", ptr);
		EDMA3CCPaRAMEntry param;
		EDMA3GetPaRAM(&EDMA3_CC0, EDMA3_CHA_MMCSD0_TX, &param);
		syslog(LOG_ERROR, "srcAddr: 0x%08x", param.srcAddr);
	}

	/* 9. Use MMCCMD to send the WRITE_BLOCK command to the card. */
#if defined(DEBUG)
	syslog(LOG_ERROR, "%s(): Use MMCCMD to send the WRITE_BLOCK/WRITE_MULTI_BLOCK command to the card.", __FUNCTION__);
#endif
	mmcsdCmd cmd;
	cmd.flags = SD_CMDRSP_R1 | SD_CMDRSP_WRITE | SD_CMDRSP_DATA;
	cmd.arg = address;
	cmd.nblks = nblks;
	if (nblks > 1) {
	    cmd.idx = SD_CMD(25);
	    cmd.flags |= SD_CMDRSP_ABORT;
	} else {
	    cmd.idx = SD_CMD(24);
	}
	status = MMCSDCmdSend(ctrl, &cmd);
	if (status == 0) {
		syslog(LOG_ERROR, "%s(): MMCSDCmdSend() failed.", __FUNCTION__);
		goto error_exit;
	}

	// CPU Mode
//	uint32_t *buf = ptr; // Assume uint32_t is little-endian

//	while (1) {
//		EDMA3CCPaRAMEntry param;
////		syslog(LOG_ERROR, "MMCSD0.MMCST0: 0x%08x", MMCSD0.MMCST0);
////		syslog(LOG_ERROR, "MMCSD0.MMCST1: 0x%08x", MMCSD0.MMCST1);
////		syslog(LOG_ERROR, "EDMA3_CC0.ER: 0x%08x", EDMA3_CC0.ER);
////		syslog(LOG_ERROR, "EDMA3_CC0.EMR: 0x%08x", EDMA3_CC0.EMR);
////		syslog(LOG_ERROR, "EDMA3_CC0.SER: 0x%08x", EDMA3_CC0.SER);
//		EDMA3GetPaRAM(&EDMA3_CC0, EDMA3_CHA_MMCSD0_TX, &param);
////		syslog(LOG_ERROR, "origSrcAddr: 0x%08x", ptr);
//		syslog(LOG_ERROR, "srcAddr: 0x%08x", param.srcAddr);
////		syslog(LOG_ERROR, "CCNT: %d", param.cCnt);
//
//		tslp_tsk(1000);
//	}

	/* 10. Set the DMATRIG bit in MMCCMD to trigger the first data transfer. */
#if DEBUG_PRINT
//	syslog(LOG_ERROR, "%s(): Set the DMATRIG bit, MMCCMD: 0x%08x=>0x%08x", __FUNCTION__, mmc->MMCCMD, mmc->MMCCMD | MMCSD_MMCCMD_DMATRIG);
#endif
//	mmc->MMCCMD /*|*/= MMCSD_MMCCMD_DMATRIG;

	/* 11. Wait for DMA sequence to complete. */
	status = ctrl->xferStatusGet(ctrl);
	if (status == 0) { assert(false); goto error_exit; }

error_exit:

	return status;

#if 0
  mmcsdCardInfo *card = ctrl->card;
  unsigned int status = 0;
  unsigned int address;
  mmcsdCmd cmd;

#if DEBUG_PRINT
  UARTprintf("----\r\n");
  UARTprintf("%s(0x%x)\r\n", __FUNCTION__, ctrl);
#endif


  }
Ejemplo n.º 9
0
/**
 * Read or write block(s) from MMC/SD card. The implementation follows
 * '26.3.5 MMC/SD Mode Single-Block Read Operation Using EDMA' and
 * '26.3.3 MMC/SD Mode Single-Block Write Operation Using EDMA' in 'spruh82a'.
 * @param  mmcsdCtrlInfo It holds the mmcsd control information.
 * @param  ptr           It determines the address to store or fetch the data
 * @param  block         It determines from which block data to be read or written (block >= 0)
 * @param  nblks         It determines the number of blocks to be read or written (nblks >= 1)
 * @retval 1             success
 * @retval 0             fail
 */
static
unsigned int
MMCSDReadWriteCmdSend(mmcsdCtrlInfo *ctrl, void *ptr, unsigned int block, unsigned int nblks, bool_t rx) {
	unsigned int status = 0; // 0 for failure

	/**
	 * Handle unaligned READ operation using data_recv_buf
	 */
	if (rx && ((unsigned int)ptr % SOC_EDMA3_ALIGN_SIZE) != 0) {
		static uint8_t data_recv_buf[MMCSD_MAX_BLOCK_LEN * 8] __attribute__((aligned(SOC_EDMA3_ALIGN_SIZE)));
#define DATA_RECV_BUF_MAX_BLOCKS (sizeof(data_recv_buf) / MMCSD_MAX_BLOCK_LEN)

		for (unsigned int i = 0; i < nblks; i += DATA_RECV_BUF_MAX_BLOCKS) {
			unsigned int blocks_to_process = (i + DATA_RECV_BUF_MAX_BLOCKS <= nblks) ? DATA_RECV_BUF_MAX_BLOCKS : nblks - i;
			status = MMCSDReadWriteCmdSend(ctrl, data_recv_buf, block + i, blocks_to_process, rx);
			memcpy(ptr + i * MMCSD_MAX_BLOCK_LEN, data_recv_buf, MMCSD_MAX_BLOCK_LEN * blocks_to_process);
			if (status == 0) break;
		}
		goto error_exit;
	}

#if defined(DEBUG_MMCSD)
	syslog(LOG_NOTICE, "%s(): %s %d block(s), ptr=%p", __FUNCTION__, rx ? "Read" : "Write", nblks, ptr);
#endif

	/* 1. Write the card's relative address to the MMC argument registers (MMCARGH and MMCARGL). */
	volatile struct st_mmcsd *mmc = (struct st_mmcsd *)ctrl->memBase;
	if (!ctrl->card->highCap) { // Only SDHC card is supported by now.
		syslog(LOG_ERROR, "%s(): Standard capacity SD card is not supported, please use an SDHC card!", __FUNCTION__);
		goto error_exit;
	}
	mmc->MMCARGHL = block;
#if 0
	mmcsdCardInfo *card = ctrl->card;
	unsigned int address;
	/*
	 * Address is in blks for high cap cards and in actual bytes
	 * for standard capacity cards
	 */
	assert(card->highCap);
	if (card->highCap)
		address = block;
	else
		address = block * card->blkLen;
	mmc->MMCARGHL = address;
#endif

	/* 2. Read card CSD to determine the card's maximum block length. */
	// TODO: This step is unnecessary for SDHC card

	/* 3. Use the MMC command register (MMCCMD) to send the SET_BLOCKLEN command (if the block
	 length is different than the length used in the previous operation). The block length must be a multiple
	 of 512 bytes and less then the maximum block length specified in the CSD. */
	// TODO: This step is unnecessary for SDHC card

	/* 4. Reset the FIFO (FIFORST bit in MMCFIFOCTL). */
	mmc->MMCFIFOCTL |= MMCSD_MMCFIFOCTL_FIFORST;
	mmc->MMCFIFOCTL &= ~MMCSD_MMCFIFOCTL_FIFORST;

	/* 5. Set the FIFO direction (FIFODIR bit in MMCFIFOCTL). */
	if (rx) // FIFO to receive
		mmc->MMCFIFOCTL &= ~MMCSD_MMCFIFOCTL_FIFODIR;
	else	// FIFO to send
		mmc->MMCFIFOCTL |= MMCSD_MMCFIFOCTL_FIFODIR;

	/* 6. Set the access width (ACCWD bits in MMCFIFOCTL). */
	mmc->MMCFIFOCTL &= ~MMCSD_MMCFIFOCTL_ACCWD;
	mmc->MMCFIFOCTL |= (MMCSD_MMCFIFOCTL_ACCWD_4BYTES << MMCSD_MMCFIFOCTL_ACCWD_SHIFT); // => 4 bytes

	/* 7. Set the FIFO threshold (FIFOLEV bit in MMCFIFOCTL). */
	mmc->MMCFIFOCTL |=  MMCSD_MMCFIFOCTL_FIFOLEV; // => 64 bytes

	/* 8. Set up DMA (DMA size needs to be greater than or equal to FIFOLEV setting). */
#if defined(DEBUG_MMCSD) && 0
	syslog(LOG_NOTICE, "%s(): Set up DMA", __FUNCTION__);
#endif
	if (rx) {
		CacheDataCleanBuff(ptr, MMCSD_MAX_BLOCK_LEN * nblks); // Clean 'data_recv_buf'
		arm926_drain_write_buffer();                              // Memory barrier for 'data_recv_buf'
		ctrl->xferSetup(ctrl, 1, ptr, MMCSD_MAX_BLOCK_LEN, nblks);
	} else {
		data_cache_clean_buffer(ptr, MMCSD_MAX_BLOCK_LEN * nblks); // Clean data buffer to send
		arm926_drain_write_buffer(); // Memory barrier for data buffer to send
		ctrl->xferSetup(ctrl, 0, ptr, MMCSD_MAX_BLOCK_LEN, nblks);
	}

	/* 9. Use MMCCMD to send the READ_BLOCK/WRITE_BLOCK command to the card. */
#if defined(DEBUG_MMCSD) && 0
	syslog(LOG_NOTICE, "%s(): Send READ/WRITE command", __FUNCTION__);
#endif
	mmcsdCmd cmd;
	if (rx) {
		cmd.flags = SD_CMDRSP_R1 | SD_CMDRSP_READ | SD_CMDRSP_DATA;
		cmd.idx = SD_CMD(17);
		cmd.nblks = nblks;
		if (nblks > 1) {
			cmd.flags |= SD_CMDRSP_ABORT;
			cmd.idx = SD_CMD(18);
		} else {
			cmd.idx = SD_CMD(17);
		}
	} else {
		cmd.flags = SD_CMDRSP_R1 | SD_CMDRSP_WRITE | SD_CMDRSP_DATA;
		cmd.idx = SD_CMD(24);
		cmd.nblks = nblks;
		if (nblks > 1) {
		    cmd.idx = SD_CMD(25);
		    cmd.flags |= SD_CMDRSP_ABORT;
		} else {
		    cmd.idx = SD_CMD(24);
		}
	}

	status = MMCSDCmdSend(ctrl, &cmd);
	if (status == 0) {
		syslog(LOG_ERROR, "%s(): MMCSDCmdSend() failed.", __FUNCTION__);
		goto error_exit;
	}

	/* 10. Set the DMATRIG bit in MMCCMD to trigger the first data transfer. */
	// TODO: This step has already been done by last step.
	//mmc->MMCCMD |= MMCSD_MMCCMD_DMATRIG;

	/* 11. Wait for DMA sequence to complete. */
#if defined(DEBUG_MMCSD) && 0
	syslog(LOG_NOTICE, "%s(): Wait for DMA sequence to complete", __FUNCTION__);
#endif
	status = ctrl->xferStatusGet(ctrl);

	if (status == 0) {
		assert(false);
		goto error_exit;
	}
	if (rx) { // Copy data received
		CacheDataInvalidateBuff((unsigned int) ptr, MMCSD_MAX_BLOCK_LEN * nblks); // Invalidate the data cache.
	}

    /* 12. Use the MMC status register 0 (MMCST0) to check for errors. */
	if (rx || nblks == 1) {
#if defined(DEBUG_MMCSD) && 0
	syslog(LOG_NOTICE, "%s(): Wait for DATDNE", __FUNCTION__);
#endif
		ctrl->waitMMCST0(ctrl, MMCSD_MMCST0_DATDNE);
	}

	/* 13. Use MMCCMD to send the STOP_TRANSMISSION command. */
	if (cmd.nblks > 1) {
#if defined(DEBUG_MMCSD) && 0
	syslog(LOG_NOTICE, "%s(): Send STOP_TRANSMISSION", __FUNCTION__);
#endif
		status = MMCSDStopCmdSend(ctrl);
		assert(status != 0);

		ctrl->waitMMCST0(ctrl, MMCSD_MMCST0_BSYDNE);
		//while(HWREG(ctrl->memBase + MMCSD_MMCST1) & MMCSD_MMCST1_BUSY);
	}

error_exit:
	return status;
}
Ejemplo n.º 10
0
/**
 * Read block(s) from MMC/SD card. The implementation follows
 * '26.3.5 MMC/SD Mode Single-Block Read Operation Using EDMA' in 'spruh82a'.
 * @param  mmcsdCtrlInfo It holds the mmcsd control information.
 * @param  ptr           It determines the address to where data has to read
 * @param  block         It determines from which block data to be read (block >= 0)
 * @param  nblks         It determines the number of blocks to be read (nblks >= 1)
 * @retval 1             success
 * @retval 0             fail
 */
unsigned int
MMCSDReadCmdSend(mmcsdCtrlInfo *ctrl, void *ptr, unsigned int block, unsigned int nblks) {

	// TODO: workaround for buggy READ_MULTI_BLOCK
	if (nblks > 1) {
		for (unsigned int i = 0; i < nblks; ++i) {
			unsigned int res = MMCSDReadCmdSend(ctrl, ptr + i * MMCSD_MAX_BLOCK_LEN, block + i, 1);
			assert(res == 1);
		}
		return 1;
	}
	assert(nblks == 1);

#if defined(DEBUG)
//	UARTprintf("----\r\n");
//	UARTprintf("%s(0x%x)\r\n", __FUNCTION__, ctrl);
//	syslog(LOG_ERROR, "----");
	syslog(LOG_ERROR, "%s(ctrl=0x%p,ptr=0x%p,block=%d,nblks=%d)", __FUNCTION__, ctrl, ptr, block, nblks);
#endif
	assert(nblks * MMCSD_MAX_BLOCK_LEN <= sizeof(data_recv_buf));
//	MMCSDDataTimeoutSet(ctrl->memBase, 0x0, 0x3FFFFFF);// Infinite wait for CMD response, maximum wait for data transfer
//	cmdTimeout = 0; // TODO: fix this (refactoring)
//	for(int i = 0; i < sizeof(data_recv_buf); ++i) data_recv_buf[i] = 0xFF; // Fill data_recv_buf for debug


	unsigned int status = 1; // 1 for success
	volatile struct st_mmcsd *mmc = ctrl->memBase;
	ER ercd;

	/* 1. Write the card's relative address to the MMC argument registers (MMCARGH and MMCARGL). */
	mmcsdCardInfo *card = ctrl->card;
	unsigned int address;
	/*
	 * TODO: check this -- ertl-liyixiao
	 * Address is in blks for high cap cards and in actual bytes
	 * for standard capacity cards
	 */
	assert(card->highCap);
	if (card->highCap)
		address = block;
	else
		address = block * card->blkLen;
	mmc->MMCARGHL = address;

	/* 2. Read card CSD to determine the card's maximum block length. */
	// TODO:

	/* 3. Use the MMC command register (MMCCMD) to send the SET_BLOCKLEN command (if the block
	 length is different than the length used in the previous operation). The block length must be a multiple
	 of 512 bytes and less then the maximum block length specified in the CSD. */
	// TODO:

	/* 4. Reset the FIFO (FIFORST bit in MMCFIFOCTL). */
	mmc->MMCFIFOCTL |= MMCSD_MMCFIFOCTL_FIFORST;
	mmc->MMCFIFOCTL &= ~MMCSD_MMCFIFOCTL_FIFORST;

	/* 5. Set the FIFO direction to receive (FIFODIR bit in MMCFIFOCTL). */
	mmc->MMCFIFOCTL &= ~MMCSD_MMCFIFOCTL_FIFODIR;

	/* 6. Set the access width (ACCWD bits in MMCFIFOCTL). */
	mmc->MMCFIFOCTL &= ~MMCSD_MMCFIFOCTL_ACCWD;
	mmc->MMCFIFOCTL |= (MMCSD_MMCFIFOCTL_ACCWD_4BYTES << MMCSD_MMCFIFOCTL_ACCWD_SHIFT); // => 4 bytes

	/* 7. Set the FIFO threshold (FIFOLEV bit in MMCFIFOCTL). */
	mmc->MMCFIFOCTL |=  MMCSD_MMCFIFOCTL_FIFOLEV; // => 64 bytes

	/* 8. Set up DMA (DMA size needs to be greater than or equal to FIFOLEV setting). */
	CacheDataCleanBuff(data_recv_buf, sizeof(data_recv_buf)); // Clean 'data_recv_buf'
	arm926_drain_write_buffer();                              // Memory barrier for 'data_recv_buf'
	ctrl->xferSetup(ctrl, 1, data_recv_buf/*ptr*/, MMCSD_MAX_BLOCK_LEN, nblks);

	/* 9. Use MMCCMD to send the READ_BLOCK command to the card. */
#if defined(DEBUG)
	syslog(LOG_ERROR, "%s(): Use MMCCMD to send the READ_BLOCK/READ_MULTI_BLOCK command to the card.", __FUNCTION__);
#endif
//	ercd = clr_flg(MMCSD_ISR_FLG, ~(MMCSD_ISR_FLGPTN_DATATIMEOUT)); // Clear data time-out flag
//	mmc->MMCIM |= MMCSD_MMCIM_ETOUTRD; // Enable data time-out interrupt
	assert(ercd == E_OK);
	mmcsdCmd cmd;
	cmd.flags = SD_CMDRSP_R1 | SD_CMDRSP_READ | SD_CMDRSP_DATA;
	cmd.arg = address;
	cmd.nblks = nblks;
	if (nblks > 1) {
		cmd.flags |= SD_CMDRSP_ABORT;
		cmd.idx = SD_CMD(18);
	} else {
		cmd.idx = SD_CMD(17);
	}
	status = MMCSDCmdSend(ctrl, &cmd);
	if (status == 0) {
		syslog(LOG_ERROR, "%s(): MMCSDCmdSend() failed.", __FUNCTION__);
		goto error_exit;
	}

	/* 10. Set the DMATRIG bit in MMCCMD to trigger the first data transfer. */
#if DEBUG_PRINT
//	syslog(LOG_ERROR, "%s(): Set the DMATRIG bit, MMCCMD: 0x%08x=>0x%08x", __FUNCTION__, mmc->MMCCMD, mmc->MMCCMD | MMCSD_MMCCMD_DMATRIG);
#endif
//	mmc->MMCCMD /*|*/= MMCSD_MMCCMD_DMATRIG;

	/* 11. Wait for DMA sequence to complete. */
	status = ctrl->xferStatusGet(ctrl);
	if (status == 0) { assert(false); goto error_exit; }

	/* Invalidate the data cache. */
	CacheDataInvalidateBuff((unsigned int) data_recv_buf/*ptr*/, (MMCSD_MAX_BLOCK_LEN * nblks));

    /* 12. Use the MMC status register 0 (MMCST0) to check for errors. */
	// TODO: check this
#if 0
	syslog(LOG_ERROR, "%s(): MMCST0: 0x%08x", __FUNCTION__, mmc->MMCST0);
	syslog(LOG_ERROR, "%s(): MMCST1: 0x%08x", __FUNCTION__, mmc->MMCST1);
	syslog(LOG_ERROR, "%s(): MMCNBLK: %d", __FUNCTION__, mmc->MMCNBLK);
	syslog(LOG_ERROR, "%s(): MMCNBLC: %d", __FUNCTION__, mmc->MMCNBLC);
#endif


	assert(sizeof(data_recv_buf) >= MMCSD_MAX_BLOCK_LEN * nblks);
	memcpy(ptr, data_recv_buf, MMCSD_MAX_BLOCK_LEN * nblks);

	  // TODO: ertl-liyixiao
#if defined(DEBUG)
	syslog(LOG_ERROR, "%s sector: %d, count: %d\n", __FUNCTION__, block, nblks);
	  for(int i = 0; i < MMCSD_MAX_BLOCK_LEN * nblks;) {
		  //((uint8_t*)ptr)[i] = ((uint8_t*)ptr)[i];
		  uint8_t *val = ((uint8_t*)ptr) + i;
		  syslog(LOG_ERROR, "%02x %02x %02x %02x %02x", val[0], val[1], val[2], val[3], val[4]);
		  //printf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \n",
		  //	  val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], val[12], val[13], val[14], val[15]);
		  i += 5;
	  }
#endif

#if 0 // TODO: !IMPORTANT! STOP_TRANSMISSION must not be sent since MMCSD_MMCNBLK has been set to the exact number.
	/* Send a STOP_TRANSMISSION after reading multiple blocks */
	if (cmd.nblks > 1) {
		status = MMCSDStopCmdSend(ctrl);
		assert(status != 0); // TODO: check status
	}
#endif

error_exit:

//	mmc->MMCIM &= ~MMCSD_MMCIM_ETOUTRD; // Disable data time-out interrupt TODO: fix me

	return status;

#if 0


  // TODO: -- ertl-liyixiao
#ifdef CACHE_SUPPORTED
  /* Clean the data cache. */
  CacheDataCleanBuff((unsigned int) ptr, (MMCSD_MAX_BLOCK_LEN * nblks));
#endif
  mmcsd_reset_fifo(true);

  /* Send a STOP */
  if (cmd.nblks > 1)
  {
    status = MMCSDStopCmdSend(ctrl);

    if (status == 0)
    {
#if DEBUG_PRINT
      UARTprintf("%s(0x%x):MMCSDStopCmdSend() returned 0\r\n", __FUNCTION__, ctrl);
#endif
      return 0;
    }
  }

#endif
}
Ejemplo n.º 11
0
unsigned int MMCSDCardInit(mmcsdCtrlInfo *ctrl)
{

    mmcsdCardInfo *card = ctrl->card;
    unsigned int retry = 0xFFFF;
    unsigned int status = 0;
    unsigned int khz;
    mmcsdCmd cmd;

    memset(ctrl->card, 0, sizeof(mmcsdCardInfo));

    card->ctrl = ctrl;

	/* CMD0 - reset card */
	status = MMCSDCardReset(ctrl);

	if (status == 0)
	{
		card->error = 1;
		return 0;
	}
	//mmc card initialization


    ctrl->card->cardType = MMCSD_CARD_MMC;
    //open drain для команд инициализации
    HWREG(ctrl->memBase + MMCHS_CON) |= MMCHS_CON_OD;

    //Set SD_SYSCTL[25] SRC
    //bit to 0x1 and wait until it returns to 0x0
    HWREG(ctrl->memBase + MMCHS_SYSCTL) |= MMCHS_SYSCTL_SRC;
    while(!(HWREG(ctrl->memBase + MMCHS_SYSCTL) & MMCHS_SYSCTL_SRC));
    while(HWREG(ctrl->memBase + MMCHS_SYSCTL) & MMCHS_SYSCTL_SRC);

   /* CMD1 - SEND_OP_COND */
    retry = RETRY; //с потолка
    cmd.idx = SD_CMD(1);
    cmd.flags = 0;
    cmd.arg = 0x40ff8080;/////карта больше 2 Гб?
    cmd.rsp[0] = 0;
do{
	status = ctrl->cmdSend(ctrl, &cmd);
	if (status == 0) {
    	card->error = 1;
    	return status; //если нет ответа, можно выходить
	}
	//добавил задержку для кривой eMMC СОТА
	delay(10);

} while (!(cmd.rsp[0] & ((unsigned int)BIT(31))) && retry--);

	if (0xffffffff == retry) //карта до 2 Гб?
	{
		retry = RETRY; //c потолка
        cmd.arg = 0x00ff8080; //волшебная цыфорка
		do{
			status = ctrl->cmdSend(ctrl, &cmd);
			if (status == 0) {
		    	card->error = 1;
		    	return status; //если нет ответа, можно выходить
			}
			//добавил задержку для кривой eMMC СОТА
			delay(10);
		} while (!(cmd.rsp[0] & ((unsigned int)BIT(31))) && retry--);

	}
	if (0xffffffff == retry) {
    	card->error = 1;
		return 0;
	}

	//сохраняем OCR
    card->ocr = cmd.rsp[0];
    card->highCap = (card->ocr & SD_OCR_HIGH_CAPACITY) ? 1 : 0;

   /* CMD2 - ALL_SEND_CID */
    cmd.idx = SD_CMD(2);
    cmd.flags = SD_CMDRSP_136BITS;
    cmd.arg = 0;
	status = ctrl->cmdSend(ctrl, &cmd);
	if (status == 0) {
    	card->error = 1;
    	return status; //если нет ответа, можно выходить
	}

	//Сохраняем CID карты
    memcpy(card->raw_cid, cmd.rsp, 16);

  /* CMD3 - SET_RELATIVE_ADDR */
    cmd.idx = SD_CMD(3);
    cmd.flags = 0;
    cmd.arg = 2 << 16;
	status = ctrl->cmdSend(ctrl, &cmd);
	if (status == 0) {
    	card->error = 1;
    	return status; //если нет ответа, можно выходить
	}

    card->rca = 2; //тупо

    //вырубаем open drain для команд инициализации
    HWREG(ctrl->memBase + MMCHS_CON) &= ~MMCHS_CON_OD;


    /* Send CMD9, to get the card specific data */
     cmd.idx = SD_CMD(9);
     cmd.flags = SD_CMDRSP_136BITS;
     cmd.arg = card->rca << 16;

		status = ctrl->cmdSend(ctrl, &cmd);
		if (status == 0) {
	    	card->error = 1;
	    	return status; //если нет ответа, можно выходить
		}

     memcpy(card->raw_csd, cmd.rsp, 16);

     card->sd_ver =  SD_CARD_CSD_VERSION(card);
     card->tranSpeed = SD_CARD0_TRANSPEED(card);

     //Меняем тактовую частоту на повыше
     //если где-то еще используется - запихнуть в функцию
     switch (card->tranSpeed & 0x00000007) {
     case 0:
    	 khz = 100e3;
    	 break;
     case 1:
      	 khz = 1000e3;
       	 break;
     case 2:
       	 khz = 10000e3;
      	 break;
     case 3:
       	 khz = 100000e3;
      	 break;
     default:
         UARTPuts("TRAN_SPEED incorrect value read", -1);
         card->error = 1;
    	 return 0;
     }
     switch ((card->tranSpeed) >> 3) {
     case 1:
    	 ctrl->opClk = 1 * khz;
    	 break;
     case 2:
    	 ctrl->opClk = 1.2 * khz;
    	 break;
     case 3:
    	 ctrl->opClk = 1.3 * khz;
    	 break;
     case 4:
    	 ctrl->opClk = 1.5 * khz;
    	 break;
     case 5:
    	 ctrl->opClk = 2 * khz;
    	 break;
     case 6:
    	 ctrl->opClk = 2.6 * khz;
    	 break;
     case 7:
    	 ctrl->opClk = 3 * khz;
    	 break;
     case 8:
    	 ctrl->opClk = 3.5 * khz;
    	 break;
     case 9:
    	 ctrl->opClk = 4 * khz;
    	 break;
     case 10:
    	 ctrl->opClk = 4.5 * khz;
    	 break;
     case 11:
    	 ctrl->opClk = 5.2 * khz;
    	 break;
     case 12:
    	 ctrl->opClk = 5.5 * khz;
    	 break;
     case 13:
    	 ctrl->opClk = 6 * khz;
    	 break;
     case 14:
    	 ctrl->opClk = 7 * khz;
    	 break;
     case 15:
    	 ctrl->opClk = 8 * khz;
    	 break;
     default:
         UARTPuts("TRAN_SPEED incorrect value read", -1);
         card->error = 1;
    	 return 0;
     }
     status = ctrl->busFreqConfig(ctrl, ctrl->opClk);

     if (status != 0) //эта функция возвращает ноль при успехе
     {
    	 card->error = 1;
         UARTPuts("HS MMC/SD TRAN_SPEED freqval set failed\n\r", -1);
         return 0;
     }

    //если спецификация вер. 4.0 и выше
     if (card->sd_ver > 3)
	 {
         /* Send CMD7 select card */
          cmd.idx = SD_CMD(7);
          cmd.flags = 0; //ответ R1
          cmd.arg = card->rca << 16;

  		status = ctrl->cmdSend(ctrl, &cmd);
 		if (status == 0) {
 			card->error = 1;
 			return status;
 		}

#if 0 //говнокод
 		if ((cmd.rsp[0] & BIT(25))) //если карта залочена стираем нафиг с нее все
 		{
 			//устанавливаем длину блока 1 байт
 	        /* Send CMD16 */
 	        cmd.idx = SD_CMD(16);
 	        cmd.flags = 0; //ответ R1
 	        cmd.arg = 1; //1 байт длина блока
 	   		status = ctrl->cmdSend(ctrl, &cmd);
 	 		if (status == 0) {
 	 			card->error = 1;
 	 			return status;
 	 		}

 	  		dataBuffer[0] = BIT(3); //Force-erase bit
 	  		dataBuffer[1] = 0; //Force-erase bit
 	  		dataBuffer[2] = 0; //Force-erase bit
 	  		dataBuffer[3] = BIT(3); //Force-erase bit

#ifdef CACHE
		  /* Invalidate the data cache. */
 			CacheDataCleanBuff((unsigned int)dataBuffer, 4);
#endif
 			ctrl->xferSetup(ctrl, 0/*0 - WRITE*/, dataBuffer, 1, 1); //Achtung! посылка одного байта
 			cmd.idx = SD_CMD(42);
 			cmd.flags = SD_CMDRSP_WRITE | SD_CMDRSP_DATA | (ctrl->dmaEnable << SD_CMDRSP_DMAEN_OFFSET);
 			cmd.arg = 0;
 			cmd.nblks = 1;
 			cmd.data = (signed char*)dataBuffer;
 			status = ctrl->cmdSend(ctrl, &cmd);
 	 		if (status == 0) {
 	 			card->error = 1;
 	 			return status;
 	 		}

 			status = ctrl->xferStatusGet(ctrl);

// 			if (status == 0) return 0;

 			//проверяем статус карты
 	        cmd.idx = SD_CMD(13);
 	        cmd.flags = 0; //ответ R1
 	        cmd.arg = card->rca << 16; //1 байт длина блока
 	   		status = ctrl->cmdSend(ctrl, &cmd);
 	 		if (status == 0) {
 	 			card->error = 1;
 	 			return status;
 	 		}


			//ждем пока карта не снимет busy!
	        while (!(HWREG(ctrl->memBase + MMCHS_PSTATE) & (unsigned int)BIT(20)));

 			//возвращаем длину блока в нормальное состояние
 	        /* Send CMD16 */
 	        cmd.idx = SD_CMD(16);
 	        cmd.flags = 0; //ответ R1
 	        cmd.arg = 512; //512 байт длина блока
 	   		status = ctrl->cmdSend(ctrl, &cmd);
 	 		if (status == 0) {
 	 			card->error = 1;
 	 			return status;
 	 		}
	  		while(1);
 		}
#endif

    	 //надо затянуть EXT_CSD
		  ctrl->xferSetup(ctrl, 1, dataBuffer, 512, 1);
		  cmd.idx = SD_CMD(8);
		  cmd.flags = SD_CMDRSP_READ | SD_CMDRSP_DATA | (ctrl->dmaEnable << SD_CMDRSP_DMAEN_OFFSET);
		  cmd.arg = 0;
		  cmd.nblks = 1;
		  cmd.data = (signed char*)dataBuffer;
		  status = ctrl->cmdSend(ctrl, &cmd);
	 		if (status == 0) {
	 			card->error = 1;
	 			return status;
	 		}

		  status = ctrl->xferStatusGet(ctrl);
	 		if (status == 0) {
	 			card->error = 1;
	 			return status;
	 		}
#ifdef CACHE
		  /* Invalidate the data cache. */
		  CacheDataInvalidateBuff((unsigned int)dataBuffer, DATA_RESPONSE_WIDTH);
#endif
	}
     else
     {
    	 UARTPuts("Old Slowpoke eMMC card\n\r", -1);
     }

     //разное определение размера карты для highCap карт  и обычных карт
     if (!(card->highCap))
     { //не факт, что работает для !highCap
		 card->blkLen = 1 << (SD_CARD0_RDBLKLEN(card));
		 card->size = SD_CARD0_SIZE(card);
		 card->nBlks = card->size / card->blkLen;

    /* Set data block length to 512 (for byte addressing cards) */
		 if (card->blkLen != 512)
		 {
			 cmd.idx = SD_CMD(16);
			 cmd.flags = 0; //resp R1
			 cmd.arg = 512;
			 status = ctrl->cmdSend(ctrl, &cmd);

		 		if (status == 0) {
		 			card->error = 1;
		 			return status;
		 		}
			 else
			 {
				 card->blkLen = 512;
			 }

		 }
     }
     else //highcap - берем sector size из EXT_CSD
     {
		  //надо сохранить нужную инфу из EXT_CSD на будущее
		  //пока только SEC_COUNT
		 card->blkLen = 512;
		 card->nBlks = (dataBuffer[212] << 0) |
				  (dataBuffer[213] << 8) |
				  (dataBuffer[214] << 16) |
				  (dataBuffer[215] << 24);
		 card->size = card->nBlks; //для highcap карты размер в секторах
     }
     card->busWidth = 1;
#if 0 //деселект рабочий но забили на него - карта у нас одна
     //deselect card
     /* Send CMD7 select card */
    cmd.idx = SD_CMD(7);
    cmd.flags = SD_CMDRSP_NONE; //ответ R1
    cmd.arg = 0; //rca = 0
	status = ctrl->cmdSend(ctrl, &cmd);
		if (status == 0) return status;
#endif
	//end emmc initialization
    return 1;
}