📄 sdhc_core.cpp
字号:
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 + -