⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdhc_core.cpp

📁 NXP LPC3000系列 wince BSP包
💻 CPP
📖 第 1 页 / 共 4 页
字号:
			m_pSDCardRegs->sd_clear = 0xFFFFF;
			m_pSDCardRegs->sd_mask0 &= ~m_SD0CmdMask;
		}
	}
	else
	{
		m_pSDCardRegs->sd_cmd &= ~SD_CPST_EN;
		m_pSDCardRegs->sd_clear = 0xFFFFF;
		m_pSDCardRegs->sd_mask0 &= ~m_SD0CmdMask;
	}
}

//********************************************************************
// SD card controller support functions
//********************************************************************

//------------------------------------------------------------------------------
//
// sdCardClearController
//
// Clear/reset SD card controller to default idle state, may be used
// to clear a function that failed or timed out
//
void sdCardController::sdCardClearController(void)
{
	volatile UINT32 tmp;

	if (m_hardwareInitialized == TRUE)
	{
		m_pSDCardRegs->sd_cmd = 0; // Command state machine disabled
		m_pSDCardRegs->sd_dctrl = SD_BLKSIZE_512BYTES; // Data state machine disabled, 512 byte block
		m_pSDCardRegs->sd_mask0 = 0; // SD0 interrupts masked
		m_pSDCardRegs->sd_mask1 = 0; // SD1 interrupts masked
		m_pSDCardRegs->sd_clear = 0xFF7FF; // All status cleared
		m_pSDCardRegs->sd_dtimer = 0xFFFFFF; // Default timeout period in clocks

		// Empty the FIFO
		while ((m_pSDCardRegs->sd_status & SD_FIFO_RXDATA_AVAIL) != 0)
		{
			tmp = m_pSDCardRegs->sd_fifo [0];
		}
	}
}

//------------------------------------------------------------------------------
//
// sdCardEnableClocks
//
// Stops or starts the SD clocks (in the CLKPWR controller)
//
void sdCardController::sdCardEnableClocks(BOOL enable)
{
	if (enable == FALSE)
	{
		// Disable SD card controller clocking
		m_pClkPwrRegs->clkpwr_ms_ctrl &= ~CLKPWR_MSCARD_SDCARD_EN;
	}
	else
	{
		// Enable SD card controller clocking
		m_pClkPwrRegs->clkpwr_ms_ctrl |= CLKPWR_MSCARD_SDCARD_EN;
	}
}

//------------------------------------------------------------------------------
//
// sdCardSetClockRate
//
//  Set clock rate based on HC capability
//
void sdCardController::sdCardSetClockRate(PDWORD pdwRate)
{
	UINT32 tmp, sddiv, sdclk, bytesret;

	// Get base clock rate for SD card controller block
	if (KernelIoControl(IOCTL_LPC32XX_GETARMCLK, NULL, 0, &sdclk,
		sizeof (sdclk), (LPDWORD) &bytesret) == FALSE)
	{
		// Cannot get clock, use default
        DEBUGMSG(SDHC_ERROR_ZONE, 
            (TEXT("SDHC: Error getting SD card base clock rate.\r\n")));
		sdclk = 208000000;
	}

	// Limit clock rate to registry setting
	if (*pdwRate > m_dwMaxClockRate)
	{
		*pdwRate = m_dwMaxClockRate;
	}

	// Slightly bump up clock rate by 5% to allow for better performance in
	// some cases when on the edge of a divider
	*pdwRate += (*pdwRate / 20);

	// If the clock rate is 1M or lower, set a larger divider in the CLKPWR
	// controller
	if (*pdwRate < 1000000)
	{
		tmp = m_pClkPwrRegs->clkpwr_ms_ctrl & ~(CLKPWR_MSCARD_SDCARD_DIV(0xF));
		m_pClkPwrRegs->clkpwr_ms_ctrl = tmp | CLKPWR_MSCARD_SDCARD_DIV(8);
		sdclk = sdclk / 8;
	}
	else
	{
		tmp = m_pClkPwrRegs->clkpwr_ms_ctrl & ~(CLKPWR_MSCARD_SDCARD_DIV(0xF));
		m_pClkPwrRegs->clkpwr_ms_ctrl = tmp | CLKPWR_MSCARD_SDCARD_DIV(1);
	}

	/* Find best divider to generate target clock rate */
    sddiv = 0;
	tmp = m_pSDCardRegs->sd_clock & ~(SD_CLKDIV_MASK |
		SD_SDCLK_BYPASS);
    while ((sdclk / (2 * (sddiv + 1))) >= (UINT32) *pdwRate)
    {
    	sddiv++;
    }
    if (sddiv > SD_CLKDIV_MASK)
    {
    	/* Limit to maximum supported divider */
    	sddiv = SD_CLKDIV_MASK;
    }
    else if (sddiv == 0)
    {
    	/* May have to use the clock bypass instead */
    	if ((UINT32) *pdwRate >= sdclk)
    	{
    		tmp |= SD_SDCLK_BYPASS;
    	}

		sddiv = 1;
    }

	m_pSDCardRegs->sd_clock = (tmp | sddiv);

	// Adjust bus mode based on clock speed
	if (*pdwRate > 400000)
	{
		// Switch to push-pull mode
		m_pSDCardRegs->sd_power &= ~SD_OPENDRAIN_EN;
	}
	else
	{
		m_pSDCardRegs->sd_power |= SD_OPENDRAIN_EN;
	}

    DEBUGMSG(SDHC_CLOCK_ZONE,
		(TEXT("SDHC - Clock set to %dHz (actual %d) (%x/%x/%x)\r\n"), *pdwRate,
		(sdclk / (2 * (sddiv + 1))), sdclk, sddiv, m_pSDCardRegs->sd_clock));
}

//------------------------------------------------------------------------------
//
// sdCardSetInterface
//
// Set up the controller according to the interface parameters
//
void sdCardController::sdCardSetInterface(PSD_CARD_INTERFACE pInterface)
{
    DEBUGCHK(pInterface);

    if (pInterface->InterfaceMode == SD_INTERFACE_SD_MMC_1BIT) 
    {
        DEBUGMSG(SDHC_INIT_ZONE, 
            (TEXT("SDHC - Setting for 1 bit mode\r\n")));
		m_pSDCardRegs->sd_clock &= ~SD_WIDEBUSMODE_EN;
    } 
    else if (SD_INTERFACE_SD_4BIT == pInterface->InterfaceMode) 
    {
        DEBUGMSG(SDHC_INIT_ZONE, 
            (TEXT("SHCSDSlotOptionHandler - Setting for 4 bit mode\r\n")));
		m_pSDCardRegs->sd_clock |= SD_WIDEBUSMODE_EN;
    } 
    else 
    {
        DEBUGCHK(FALSE);
    }

    sdCardSetClockRate(&pInterface->ClockRate);
}

//------------------------------------------------------------------------------
//
// sdPowerUp
//
// Power up or down the SD card controller
//
void sdCardController::sdPowerUp(BOOL powerUp)
{
	DEBUGMSG(SDHC_INIT_ZONE,
		(TEXT("sdCardController::sdPowerUp\r\n")));
	sdCardEnableClocks(powerUp);
}

//------------------------------------------------------------------------------
//
// UpdateDevicePowerState
//
// Update device power state
//
VOID sdCardController::UpdateDevicePowerState(void) 
{
	if (m_PowerState == D4)
	{
		// Restore slot power
		sdCardEnableClocks(TRUE);
		sdHwSlotPowerControl(m_pGPIORegs, TRUE);
	}
	else
	{
		; // TBD
		sdHwSlotPowerControl(m_pGPIORegs, FALSE);
		sdCardEnableClocks(FALSE);
	}
    if( m_hParentBus ) {
        SetDevicePowerState( m_hParentBus, m_PowerState, NULL );
    }
}

//------------------------------------------------------------------------------
//
// ProcessRequest
//
// Process a SD request
//
SD_API_STATUS sdCardController::ProcessRequest(PSD_BUS_REQUEST pRequest)
{
	// Save transfer parameters
	m_CommandCode = pRequest->CommandCode;
	m_CommandArgument = pRequest->CommandArgument;
	m_ResponseType = pRequest->CommandResponse.ResponseType;
	m_TransferClass = pRequest->TransferClass;

	// If the controller is busy, then exit with error status
	if ((m_pSDCardRegs->sd_status & (SD_RX_INPROGRESS | SD_TX_INPROGRESS |
		SD_CMD_INPROGRESS)) != 0)
	{
        DEBUGMSG(SDHC_BUSY_STATE_ZONE, (TEXT("Controller is busy before command sent!\r\n")));
		sdCardClearController();
		return SD_API_STATUS_UNSUCCESSFUL;
	}

	// Clear any latched SD card controller status and clear state machines
	sdCardClearController();

    DEBUGMSG(1, (TEXT("ProcessRequest (Cmd=%d, Arg=0x%08x, RespType=%d, Data=0x%x <%dx%d>) starts\r\n"), 
        m_CommandCode, m_CommandArgument, m_ResponseType, (m_TransferClass==SD_COMMAND)?FALSE:TRUE, pRequest->NumBlocks, pRequest->BlockSize ) );

	m_readbuff = (DWORD) pRequest->pBlockBuffer;

	// Setup command state machine and enable CMD state machine interrupts
	sdCmdSMSetup(m_CommandCode, m_CommandArgument, m_ResponseType);

	m_dataStatus = SD_API_STATUS_SUCCESS;
	if ((m_TransferClass == SD_READ) || (m_TransferClass == SD_WRITE))
    {
		// Setup data state machine
		m_NumBlocks = pRequest->NumBlocks;
		m_BlockSize = pRequest->BlockSize;
		m_pBlockBuffer = pRequest->pBlockBuffer;
		m_xferSize = m_BlockSize * m_NumBlocks;
		sdDataSMSetup(pRequest->DataAccessClocks);

		// Enable command and data state machine and interrupt
		if (m_TransferClass == SD_READ)
		{
			// Read commands start the data state machine now, while writes are
			// delayed until the command response is ready
			m_pSDCardRegs->sd_dctrl |= SD_DATATRANSFER_EN;
		}

		m_dataStatus = SD_API_STATUS_PENDING;
	}

	// Enable command state
	m_cmdStatus = SD_API_STATUS_PENDING;
	m_pSDCardRegs->sd_cmd |= SD_CPST_EN;

	return SD_API_STATUS_SUCCESS;
}

//------------------------------------------------------------------------------
//
// sdCmdSMSetup
//
// Setup command state machine
//
void sdCardController::sdCmdSMSetup(UINT32 commandCode,
		                            UINT32 commandArgument,
					                UINT16 responseType)
{
	UINT32 tmp;

	m_TranCheckFlag = FALSE;
	m_ProgCheckFlag = FALSE;

	// Write arg register first
	m_pSDCardRegs->sd_arg = commandArgument;

	// Save command word
	tmp = commandCode;

	// Setup response
    switch(responseType)
    {
	case NoResponse:
		// No response expected
		m_SD0CmdMask = SD_CMD_SENT;
		break;

	case ResponseR2:
		// Long response required
		tmp |= (SD_LONGRESP_EN | SD_RESPONSE);
		m_SD0CmdMask = (SD_CMD_TIMEOUT | SD_CMD_CRC_FAIL | SD_CMD_RESP_RECEIVED);
        break;

    case ResponseR1b:
		// Will need to verify transfer state after operation
		m_TranCheckFlag = TRUE;
	default:
		// Short response required
		tmp |= SD_RESPONSE;
		m_SD0CmdMask = (SD_CMD_TIMEOUT | SD_CMD_CRC_FAIL | SD_CMD_RESP_RECEIVED);

		// Write commands require a busy status check on DAT0, which the
		// hardware doesn't support
		if (commandCode == 24)
		{
			// Need to verify that programming is complete before returning
			// completion status to host
			m_ProgCheckFlag = TRUE;
		}
		break;
    }

	// Update command register
	m_pSDCardRegs->sd_cmd = tmp;

	// Clear latched command statuses and enable command state
	// machine interrupts
    m_pSDCardRegs->sd_mask0 = m_SD0CmdMask;
}

//------------------------------------------------------------------------------
//
// sdGetBlockSize
//
// Return the blocksize field for the data control state register
//
UINT32 sdCardController::sdGetBlockSize(ULONG blockSize)
{
	UINT32 ret;

	switch (blockSize)
	{
	case 1:
		ret = SD_BLKSIZE_1BYTE;
		break;
	case 2:
		ret = SD_BLKSIZE_2BYTES;
		break;
	case 4:
		ret = SD_BLKSIZE_4BYTES;
		break;
	case 8:
		ret = SD_BLKSIZE_8BYTES;
		break;
	case 16:
		ret = SD_BLKSIZE_16BYTES;
		break;
	case 32:
		ret = SD_BLKSIZE_32BYTES;
		break;
	case 64:
		ret = SD_BLKSIZE_64BYTES;
		break;
	case 128:
		ret = SD_BLKSIZE_128BYTES;
		break;
	case 256:
		ret = SD_BLKSIZE_256BYTES;
		break;
	case 512:
	default:
		ret = SD_BLKSIZE_512BYTES;
		break;
	case 1024:
		ret = SD_BLKSIZE_1024BYTES;
		break;
	case 2048:
		ret = SD_BLKSIZE_2048BYTES;
		break;
	}

	return ret;
}

//------------------------------------------------------------------------------
//
// sdDataSMSetup
//
// Setup data state machine
//
void sdCardController::sdDataSMSetup(DWORD timeout)
{
	UINT32 tmp;

	// Set the data size to transfer
	m_pSDCardRegs->sd_dlen = m_xferSize;

	// Setup data interrupt mask
	m_SD1DataMask = (SD_DATA_CRC_FAIL | SD_DATA_TIMEOUT | SD_DATA_END |
		SD_STARTBIT_ERR);

	// Set blocksize and enable DMA
	tmp = (SD_DMA_EN | sdGetBlockSize(m_BlockSize));

	// Set direction based on transfer mode
	if (m_TransferClass == SD_READ)
	{
		// Enable read interrupts and set direction for read
		m_SD1DataMask |= SD_FIFO_RXDATA_OFLOW;
		tmp |= SD_DIR_FROMCARD;
	}
	else
	{
		// Enable write interrupts
		m_SD1DataMask |= SD_FIFO_TXDATA_UFLOW;

		// Move data to DMA area
		SDPerformSafeCopy((void *) m_dmaTXBuffVirt, m_pBlockBuffer,
			m_xferSize);
	}

	// Setup data state machine and enable interrupts
	m_pSDCardRegs->sd_dctrl = tmp;
    m_pSDCardRegs->sd_mask0 |= m_SD1DataMask;

	// Set data timeout
	m_pSDCardRegs->sd_dtimer = (m_dataTimeout + timeout);

	// Read or write?
	if (m_TransferClass == SD_READ)
	{
		// Submit buffer to hardware
		dmaTranEntry(m_dmaRXCtl, (DWORD) &SDCARD->sd_fifo[0],
			(DWORD) m_dmaRXBuffPhy, 0);
	}
	else
	{
		// Submit buffer to hardware
		dmaTranEntry(m_dmaTXCtl, (DWORD) m_dmaTXBuffPhy,
			(DWORD) &SDCARD->sd_fifo[0], 0);
	}
}

//------------------------------------------------------------------------------
//
// sdRespCopy
//
// Copy the response from the hardware
//
void sdCardController::sdRespCopy(PUCHAR buff)
{
	UINT32 tmp;

	if ((m_pSDCardRegs->sd_status & SD_CMD_RESP_RECEIVED) != 0)
	{
		// No response
		return;
	}

	tmp = m_pSDCardRegs->sd_resp [0];

	switch(m_ResponseType)
    {
	case NoResponse:
		break;

    case ResponseR1b:
    case ResponseR1:
		*(buff + 0) = (BYTE) (START_BIT | TRANSMISSION_BIT | m_pSDCardRegs->sd_respcmd);
		*(buff + 1) = (BYTE) (tmp >> 0);
		*(buff + 2) = (BYTE) (tmp >> 8);
		*(buff + 3) = (BYTE) (tmp >> 16);
		*(buff + 4) = (BYTE) (tmp >> 24);
		*(buff + 5) = (END_RESERVED | END_BIT);
		break;

    case ResponseR2:
		*(buff + 12) = (BYTE) (tmp >> 0);
		*(buff + 13) = (BYTE) (tmp >> 8);
		*(buff + 14) = (BYTE) (tmp >> 16);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -