📄 sdhc.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
// Portions Copyright (c) Texas Instruments. All rights reserved.
//
// Copyright (c) 2002 BSQUARE Corporation. All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE
// SDHC controller driver implementation
#pragma optimize("",off) // DEBUG
#include <SDCardDDK.h>
#include "SDHC.h"
#include <nkintr.h>
#include <pm.h>
#include <twl.h>
//------------------------------------------------------------------------------
// Local Structures
//Debug the Power IOCTL's
//#define PM_TRACE 0
#define SDCARD_ZONE_POWER DEBUGZONE(0)
#define DEFAULT_TIMEOUT_VALUE 60000
#define START_BIT 0x00
#define TRANSMISSION_BIT 0x00
#define START_RESERVED 0x3F
#define END_RESERVED 0xFE
#define END_BIT 0x01
#define WAIT_FOR_INTERRUPT_TIMEOUT 500 // Time in milliseconds
#define IndicateSlotStateChange(event) \
SDHCDIndicateSlotStateChange(m_pHCContext, \
(UCHAR) 0, (event))
#define GetAndLockCurrentRequest() \
SDHCDGetAndLockCurrentRequest(m_pHCContext, (UCHAR) 0)
#define TRANSFER_IS_WRITE(pRequest) (SD_WRITE == (pRequest)->TransferClass)
#define TRANSFER_IS_READ(pRequest) (SD_READ == (pRequest)->TransferClass)
#define TRANSFER_IS_COMMAND_ONLY(pRequest) (SD_COMMAND == (pRequest)->TransferClass)
#define TRANSFER_SIZE(pRequest) ((pRequest)->BlockSize * (pRequest)->NumBlocks)
static const GUID DEVICE_IFC_GPIO_GUID;
static const GUID DEVICE_IFC_TWL_GUID;
#ifdef DEBUG
// dump the current request info to the debugger
static
VOID
DumpRequest(
PSD_BUS_REQUEST pRequest
)
{
DEBUGCHK(pRequest);
DEBUGMSG(SDCARD_ZONE_INIT, (L"DumpCurrentRequest: 0x%08X\r\n", pRequest));
DEBUGMSG(SDCARD_ZONE_INIT, (L"\t Command: %d\r\n", pRequest->CommandCode));
DEBUGMSG(SDCARD_ZONE_INIT, (L"\t ResponseType: %d\r\n", pRequest->CommandResponse.ResponseType));
DEBUGMSG(SDCARD_ZONE_INIT, (L"\t NumBlocks: %d\r\n", pRequest->NumBlocks));
DEBUGMSG(SDCARD_ZONE_INIT, (L"\t BlockSize: %d\r\n", pRequest->BlockSize));
DEBUGMSG(SDCARD_ZONE_INIT, (L"\t HCParam: %d\r\n", pRequest->HCParam));
}
#else
#define DumpRequest(ptr)
#endif
#if defined(DEBUG) || defined(ENABLE_RETAIL_OUTPUT)
#define HEXBUFSIZE 1024
char szHexBuf[HEXBUFSIZE];
#endif
struct CMD
{
BYTE Cmd; // 1 - this is a known SD CMD; 2 - this is a known SDIO CMD
BYTE ACmd; // 1 - this is a known ACMD
BYTE MMCCmd; // 1 - this is a known MMC CMD
WORD CMD_TYPE;
WORD ACMD_TYPE;
WORD MMC_CMD_TYPE;
};
// table of command codes... at this time only SD/SDIO commands are implemented
const CMD gwaCMD[] =
{
{ 1, 0, 0, 0x0000, 0x2000, 0x0000 }, // CMD 00
{ 0, 0, 1, 0x1000, 0x2000, 0x1040 }, // CMD 01 (known MMC command)
{ 1, 0, 1, 0x1000, 0x2000, 0x1040 }, // CMD 02
{ 1, 0, 1, 0x1000, 0x2000, 0x1040 }, // CMD 03
{ 1, 0, 0, 0x0000, 0x2000, 0x0000 }, // CMD 04
{ 2, 0, 0, 0x1000, 0x2000, 0x1000 }, // CMD 05
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 06
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 07
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 08
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 09
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 10
{ 0, 0, 1, 0xf000, 0x2000, 0xf040 }, // CMD 11 (known MMC command)
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 12
{ 1, 1, 0, 0x2000, 0x3000, 0x2000 }, // CMD 13
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 14
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 15
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 16
{ 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 17
{ 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 18
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 19
{ 0, 1, 1, 0x7000, 0x2000, 0x7000 }, // CMD 20 (known MMC command)
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 21
{ 0, 1, 0, 0x2000, 0x3000, 0x2000 }, // CMD 22
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 23 (known MMC command)
{ 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 24
{ 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 25
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 26
{ 1, 0, 0, 0x3000, 0x2000, 0x3000 }, // CMD 27
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 28
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 29
{ 1, 0, 0, 0x3000, 0x2000, 0x3000 }, // CMD 30
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 31
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 32
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 33
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 34
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 35
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 36
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 37
{ 1, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 38
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 39 (known MMC command)
{ 1, 1, 1, 0x2000, 0x2000, 0x2040 }, // CMD 40
{ 0, 1, 0, 0x1000, 0x1000, 0x1000 }, // CMD 41 (known MMC command)
{ 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 42
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 43
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 44
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 45
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 46
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 47
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 48
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 49
{ 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 50
{ 0, 1, 0, 0xb000, 0x3000, 0xb000 }, // CMD 51 (known MMC command)
{ 2, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 52
{ 2, 0, 0, 0x3000, 0x2000, 0x3000 }, // CMD 53
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 54
{ 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 55
{ 1, 0, 0, 0x3000, 0x2000, 0x3000 }, // CMD 56
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 57
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 58
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 59
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 60
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 61
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 62
{ 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 63
};
CSDIOControllerBase::CSDIOControllerBase()
{
InitializeCriticalSection( &m_critSec );
m_fSDIOInterruptInService = FALSE;
m_fFirstTime = TRUE;
m_hControllerISTEvent = NULL;
m_htControllerIST = NULL;
m_dwControllerSysIntr = SYSINTR_UNDEFINED;
m_hCardDetectEvent = NULL;
m_htCardDetectIST = NULL;
m_dwCardDetectSysIntr = SYSINTR_UNDEFINED;
m_dwCardDetectSysIRQSize = -1;
m_fAppCmdMode = FALSE;
m_vpSDIOReg = NULL;
m_fCardPresent = FALSE;
m_fSDIOInterruptsEnabled = FALSE;
m_dwMaxTimeout = DEFAULT_TIMEOUT_VALUE;
m_bReinsertTheCard = FALSE;
m_dwWakeupSources = 0;
m_dwCurrentWakeupSources = 0;
m_fMMCMode = FALSE;
m_PowerState = D0;
}
WORD CSDIOControllerBase::Read_MMC_SDIO()
{
WORD wVal;
EnterCriticalSection( &m_critSec );
wVal = INREG16(&m_vpSDIOReg->MMC_SDIO);
LeaveCriticalSection( &m_critSec );
return wVal;
}
void CSDIOControllerBase::Write_MMC_SDIO( WORD wVal )
{
EnterCriticalSection( &m_critSec );
OUTREG16(&m_vpSDIOReg->MMC_SDIO, wVal);
LeaveCriticalSection( &m_critSec );
}
WORD CSDIOControllerBase::Read_MMC_STAT()
{
WORD wVal;
EnterCriticalSection( &m_critSec );
wVal = INREG16(&m_vpSDIOReg->MMC_STAT);
LeaveCriticalSection( &m_critSec );
return wVal;
}
void CSDIOControllerBase::Write_MMC_STAT( WORD wVal )
{
EnterCriticalSection( &m_critSec );
OUTREG16(&m_vpSDIOReg->MMC_STAT,wVal);
LeaveCriticalSection( &m_critSec );
}
// Reset the controller.
VOID CSDIOControllerBase::SoftwareReset( BYTE bResetBits )
{
WORD bValue;
DWORD dwCurrentTickCount;
DWORD dwTimeout;
DWORD dwCountStart;
BOOL fTimeoutOverflow = FALSE;
DEBUGCHK(sizeof(OMAP2420_SDIO_REGS) % sizeof(WORD) == 0);
// Reset the controller
OUTREG16(&m_vpSDIOReg->MMC_SYSC,(0x0002 & bResetBits));
// calculate timeout conditions
dwCountStart = GetTickCount();
dwTimeout = dwCountStart + m_dwMaxTimeout;
if( dwTimeout < dwCountStart )
fTimeoutOverflow = TRUE;
// Verify that reset has completed.
do {
bValue = INREG16(&m_vpSDIOReg->MMC_SISS);
// check for a timeout
dwCurrentTickCount = GetTickCount();
if( fTimeoutOverflow ? ( dwTimeout < dwCurrentTickCount && dwCurrentTickCount < dwCountStart )
: ( dwTimeout < dwCurrentTickCount || dwCurrentTickCount < dwCountStart ) )
{
DEBUGMSG(SDCARD_ZONE_ERROR, (L"CSDIOControllerBase::SoftwareReset: "
L"Exit: TIMEOUT.\r\n"
));
break;
}
} while (bValue != 0);
}
// Set up the controller according to the interface parameters.
VOID
CSDIOControllerBase::SetInterface(
PSD_CARD_INTERFACE pInterface
)
{
DEBUGCHK(pInterface);
WORD wRegValue;
if (SD_INTERFACE_SD_MMC_1BIT == pInterface->InterfaceMode)
{
DEBUGMSG(SDCARD_ZONE_INIT, (L"CSDIOControllerBase::SetInterface: "
L"Setting for 1 bit mode\r\n"
));
wRegValue = INREG16(&m_vpSDIOReg->MMC_CON);
OUTREG16(&m_vpSDIOReg->MMC_CON, (wRegValue & (~VALUE_MMC_CON_DW_4BIT)));
DEBUGMSG(SDCARD_ZONE_INIT, (L"CSDIOControllerBase::SetInterface: "
L"MMC1_CON value = %X\r\n", INREG16(&m_vpSDIOReg->MMC_CON)
));
}
else if (SD_INTERFACE_SD_4BIT == pInterface->InterfaceMode)
{
DEBUGMSG(SDCARD_ZONE_INIT, (L"CSDIOControllerBase::SetInterface: "
L"Setting for 4 bit mode \r\n"
));
wRegValue = INREG16(&m_vpSDIOReg->MMC_CON);
OUTREG16(&m_vpSDIOReg->MMC_CON, (wRegValue | (VALUE_MMC_CON_DW_4BIT)));
DEBUGMSG(SDCARD_ZONE_INIT, (L"CSDIOControllerBase::SetInterface: "
L"MMC1_CON value = %X\r\n", INREG16(&m_vpSDIOReg->MMC_CON)
));
}
else
{
DEBUGCHK(FALSE);
}
ClockOff();
SetClockRate(&pInterface->ClockRate);
ClockOn();
}
// Enable SDIO Interrupts.
VOID
CSDIOControllerBase::EnableSDIOInterrupts()
{
ASSERT( !m_fSDIOInterruptsEnabled );
DEBUGMSG(SHC_INTERRUPT_ZONE, (L"+CSDHCSlot::EnableSDIOInterrupts\r\n"));
WORD wRegValue = Read_MMC_SDIO();
wRegValue |= MMC_IE_EOC;
Write_MMC_SDIO(wRegValue);
SETREG16(&m_vpSDIOReg->MMC_IE, MMC_IE_CIRQ);
m_fSDIOInterruptsEnabled = TRUE;
}
// Acknowledge an SDIO Interrupt.
VOID CSDIOControllerBase::AckSDIOInterrupt(
)
{
ASSERT( m_fSDIOInterruptsEnabled );
DEBUGMSG(SHC_INTERRUPT_ZONE, (L"+CSDHCSlot::AckSDIOInterrupt\r\n"));
WORD wRegValue = Read_MMC_STAT();
Write_MMC_STAT(MMC_STAT_CIRQ);
wRegValue = Read_MMC_STAT();
if( wRegValue & MMC_STAT_CIRQ )
{
SDHCDIndicateSlotStateChange(m_pHCContext, 0, DeviceInterrupting);
}
else
{
SETREG16(&m_vpSDIOReg->MMC_IE, MMC_IE_CIRQ);
m_fSDIOInterruptInService = FALSE;
}
}
// Disable SDIO Interrupts.
VOID
CSDIOControllerBase::DisableSDIOInterrupts()
{
ASSERT( m_fSDIOInterruptsEnabled );
DEBUGMSG(SHC_INTERRUPT_ZONE, (L"+CSDHCSlot::DisableSDIOInterrupts\r\n"));
CLRREG16(&m_vpSDIOReg->MMC_IE, MMC_IE_CIRQ);
WORD wRegValue = Read_MMC_SDIO();
wRegValue &= (~MMC_IE_EOC);
Write_MMC_SDIO(wRegValue);
m_fSDIOInterruptsEnabled = FALSE;
}
// Set clock rate based on HC capability
VOID
CSDIOControllerBase::SetClockRate(PDWORD pdwRate)
{
const DWORD dwClockRate = *pdwRate;
// calculate the register value
WORD wDiv = (WORD)((MMCSD_CLOCK_INPUT + dwClockRate - 1) / dwClockRate);
DEBUGMSG(SHC_CLOCK_ZONE, (L"CSDIOControllerBase::SetClockRate: "
L"Actual wDiv = 0x%x requested:0x%x ", wDiv, *pdwRate
));
// Only 8 bits available for the divider, so mmc base clock / 255 is minimum.
if ( wDiv > 0x03FF )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -