Пример #1
0
unsigned int dmaRxCompletion(unsigned short usbDevInst, unsigned int ulEndpoint )
{

    unsigned int bufferAdd;
    usbInstance *usbInstance;

    hostPacketDesc *rx_bd =0;

    usbInstance = &(cppiInfo.usbInst[usbDevInst]);

    ulEndpoint = USB_EP_TO_INDEX(ulEndpoint);

    /*read the compltetion queue */
    rx_bd = (hostPacketDesc *)Cppi41DmaReadCompletionQueue(usbDevInst, usbInstance
            ->rxEndPoint[ulEndpoint].complettionq);


    bufferAdd = rx_bd->buffAdd;


    /*Flush the cache to update the buffer */
    CacheDataInvalidateBuff(rx_bd->buffAdd, rx_bd->buffLength);

    putFreeBd(rx_bd);

    return bufferAdd;
}
Пример #2
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;
}
Пример #3
0
unsigned int dmaTxCompletion(unsigned short usbDevInst, unsigned int ulEndpoint )
{

    hostPacketDesc *completed_bd;
    unsigned int ulRegister;
    unsigned int state;
    unsigned int packetid;
    usbInstance *usbInstance;

    usbInstance = &(cppiInfo.usbInst[usbDevInst]);

    ulRegister = USB_O_TXCSRL1 + EP_OFFSET( ulEndpoint);

    ulEndpoint = USB_EP_TO_INDEX(ulEndpoint);


    /*read the compltetion queue */
    completed_bd = (hostPacketDesc *)Cppi41DmaReadCompletionQueue(usbDevInst, usbInstance
                   ->txEndPoint[ulEndpoint].complettionq);
    /*Get the packet ID to update the DMA status */
    packetid = completed_bd->packetId;
    if(packetid == EOP)
        state = DMA_TX_COMPLETED;
    else
        state = DMA_TX_IN_PROGRESS;

    /*wait till Tx completion */
    if(state == DMA_TX_COMPLETED)
        while ((HWREGH(usbInstance->usbBaseAddress + ulRegister) & 0x2) == 0x02);

    CacheDataInvalidateBuff((unsigned int)completed_bd->buffAdd, sizeof(completed_bd->buffAdd));

    cppiDmaFreenBuffer((unsigned int *)completed_bd->buffAdd);

    completed_bd->buffAdd = 0;

    /*put the free buffer */
    putFreeBd(completed_bd);

    return state;

}
Пример #4
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;
}
Пример #5
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
}
Пример #6
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;
}