📄 sdpdd.c
字号:
//
// 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 OR INDEMNITIES.
//
//------------------------------------------------------------------------------
//
// File: sdpdd.c
//
// This file implements SD PDD driver.
//
//
#include <sdpdd.h>
#include <oal.h>
#include <bulverde_base_regs.h>
#include <bulverde_mmc.h>
#include <bulverde_gpio.h>
#include <bulverde_clkmgr.h>
#include <sdhcd.h>
#include <sdcard.h>
#include "sd.h"
static BOOL g_openDrainMode;
static BOOL gSendInitClocks;
static BOOL gSD4BitMode;
volatile BULVERDE_GPIO_REG *g_pGPIORegisters; // GPIO registers
volatile BULVERDE_MMC_REG *g_pSDMMCRegisters; // SD/MMC controller registers
volatile BULVERDE_CLKMGR_REG *g_pClkMgrRegisters; // Clock Manager registers
//------------------------------------------------------------------------------
//
// SDBoot - PDD Layer
//
//------------------------------------------------------------------------------
// clock rate table
typedef struct _CLOCK_RATE_ENTRY {
DWORD Frequency;
UCHAR ControlValue;
} CLOCK_RATE_ENTRY, *PCLOCK_RATE_ENTRY;
CLOCK_RATE_ENTRY SDClockTable[] =
{ {312500, 0x06},
{625000, 0x05},
{1250000, 0x04},
{2500000, 0x03},
{5000000, 0x02},
{10000000, 0x01},
{20000000, 0x00}, // 20 Mhz
};
#define NUM_CLOCK_ENTRIES sizeof(SDClockTable)/sizeof(CLOCK_RATE_ENTRY)
static UCHAR ResponseBuffer[SDCARD_RESPONSE_BUFFER_BYTES]; // largest possible reponse buffer
BOOL CLOCK_IS_ON()
{
if( g_pSDMMCRegisters->stat & MMC_STAT_CLOCK_ENABLED)
{
return TRUE;
}
else
{
return FALSE;
}
}
VOID SDClockOff()
{
// check to see if the clock is on
if (!CLOCK_IS_ON())
{
return;
}
// turn off the clock
g_pSDMMCRegisters->strpc = MMC_STRPCL_STOP_CLOCK;
while (CLOCK_IS_ON())
{
// sit here and wait for the clock to turn off
}
}
VOID SDClockOn()
{
g_pSDMMCRegisters->strpc = MMC_STRPCL_START_CLOCK;
}
VOID SDSetRate(PDWORD pRate)
{
ULONG ii; // table index variable
DWORD rate;
BOOL fClockRunning;
fClockRunning = CLOCK_IS_ON();
SDClockOff();
rate = *pRate;
// check to see if the rate is below the first entry in the table
if (rate <= SDClockTable[0].Frequency)
{
ii = 0;
}
else
{
// scan through the table looking for a frequency that
// is close to the requested rate
for (ii = 0; ii < (NUM_CLOCK_ENTRIES - 1); ii++)
{
if ((rate >= SDClockTable[ii].Frequency) &&
(rate < SDClockTable[ii+1].Frequency))
{
break;
}
}
}
// return the actual fruency
*pRate = SDClockTable[ii].Frequency;
// set the clock rate
g_pSDMMCRegisters->clkrt = SDClockTable[ii].ControlValue;
if( fClockRunning )
{
SDClockOn();
}
}
BOOL PDD_SDInitializeHardware()
{
DWORD dwRegVal; // intermediate value
gSD4BitMode = FALSE;
g_openDrainMode = FALSE;
gSendInitClocks = FALSE;
memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
g_pGPIORegisters = (BULVERDE_GPIO_REG*) OALPAtoUA(BULVERDE_BASE_REG_PA_GPIO);
g_pSDMMCRegisters = (BULVERDE_MMC_REG*) OALPAtoUA(BULVERDE_BASE_REG_PA_MMC);
g_pClkMgrRegisters = (BULVERDE_CLKMGR_REG*) OALPAtoUA(BULVERDE_BASE_REG_PA_CLKMGR);
// enable the MMC Unit Clock
g_pClkMgrRegisters->cken |= (1 << 12);
//////////////////////////////////////////////////////////
// Configure GPIO_32 as Alternate Function 2 out (MMC_CLK)
// assume that the MMC_CLK is active-low signal driven
g_pGPIORegisters->GPCR1 |= 0x00000001;
// change the direction to OUT
g_pGPIORegisters->GPDR1 |= 0x00000001;
// change to Alternate Function 2
dwRegVal = g_pGPIORegisters->GAFR1_L;
g_pGPIORegisters->GAFR1_L = ( dwRegVal & 0xfffffffc ) | 0x00000002;
//////////////////////////////////////////////////////////
// Configure GPIO_112 as Alternate Function 1 (MMC_CMD)
g_pGPIORegisters->GPSR3 |= 0x00010000;
// change the direction to OUT
g_pGPIORegisters->GPDR3 |= 0x00010000;
// change to Alternate Function 1
dwRegVal = g_pGPIORegisters->GAFR3_U;
g_pGPIORegisters->GAFR3_U = ( dwRegVal & 0xfffffffc ) | 0x00000001;
//////////////////////////////////////////////////////////
// Configure GPIO_92 as Alternate Function 1 (MMC_DAT0)
g_pGPIORegisters->GPSR2 |= 0x10000000;
// change the direction to OUT
g_pGPIORegisters->GPDR2 |= 0x10000000;
// change to Alternate Function 1
dwRegVal = g_pGPIORegisters->GAFR2_U;
g_pGPIORegisters->GAFR2_U = ( dwRegVal & 0xfcffffff ) | 0x01000000;
//////////////////////////////////////////////////////////
// Configure GPIO_93 as Card Detect
g_pGPIORegisters->GPCR2 |= 0x20000000;
// change the direction to IN
g_pGPIORegisters->GPDR2 &= 0xdfffffff;
// clear Alternate Function
dwRegVal = g_pGPIORegisters->GAFR2_U;
g_pGPIORegisters->GAFR2_U = ( dwRegVal & 0xf3ffffff );
//////////////////////////////////////////////////////////
// Configure GPIO_109-GPIO_111 as Alternate Function 1 (MMC_DAT1-MMC_DAT3)
g_pGPIORegisters->GPSR3 |= 0x0000e000;
// change the direction to OUT
g_pGPIORegisters->GPDR3 |= 0x0000e000;
// change to Alternate Function 1
dwRegVal = g_pGPIORegisters->GAFR3_L;
g_pGPIORegisters->GAFR3_L = ( dwRegVal & 0x03ffffff ) | 0x54000000;
// Check for presence of SD card (card detect pin)
if (g_pGPIORegisters->GPLR2 & 0x20000000)
{
KITLOutputDebugString("SD Card detected.\r\n");
}
else
{
return FALSE;
}
gSendInitClocks = TRUE;
return TRUE;
}
BOOL PDD_SDSendCommand(UINT8 cmd, UINT32 arg, RESP_TYPE resp, CMD_TYPE type, BOOL read)
{
DWORD cmdatRegister;
BOOL fExtraDelay = FALSE;
LONG fifoCount = 0; // starting offset in response buffer
PBYTE pSrcPtr = NULL;
UINT16 regVal = 0;
UINT32 temp=0;
volatile UINT16 *pSD_Response_Fifo = (volatile UINT16 *)&(g_pSDMMCRegisters->res);
//KITLOutputDebugString("PDD_SDSendCommand...");
SDClockOff();
memset(ResponseBuffer, 0, sizeof(ResponseBuffer));
// set the command
g_pSDMMCRegisters->cmd = cmd;
// set the argument, high part
g_pSDMMCRegisters->argh = arg >> 16;
// set the argument, high part
g_pSDMMCRegisters->argl = arg & 0x0000FFFF;
switch (resp)
{
case RESP_TYPE_NONE:
cmdatRegister = MMC_CMDAT_RESPONSE_NONE;
break;
case RESP_TYPE_R1B:
// response1 with busy signalling
cmdatRegister = MMC_CMDAT_RESPONSE_R1 | MMC_CMDAT_EXPECT_BUSY;
break;
case RESP_TYPE_R1:
case RESP_TYPE_R5:
case RESP_TYPE_R6:
// on an MMC controller R5 and R6 are really just an R1 response (CRC protected)
cmdatRegister = MMC_CMDAT_RESPONSE_R1;
break;
case RESP_TYPE_R2:
cmdatRegister = MMC_CMDAT_RESPONSE_R2;
break;
case RESP_TYPE_R3:
case RESP_TYPE_R4:
// R4 is really same as an R3 response on an MMC controller (non-CRC)
cmdatRegister = MMC_CMDAT_RESPONSE_R3;
break;
default:
return FALSE;
}
if (type == CMD_TYPE_AC ||
type == CMD_TYPE_BC ||
type == CMD_TYPE_BCR)
{
// set the length of the block
g_pSDMMCRegisters->blkle = 0;
// set the number of blocks
g_pSDMMCRegisters->nob = 0;
}
else if (type == CMD_TYPE_ADTC)
{
// set the length of the block
g_pSDMMCRegisters->blkle = BLOCK_LEN;
// set the number of blocks
g_pSDMMCRegisters->nob = 1;
// its a command with a data phase
cmdatRegister |= MMC_CMDAT_DATA_EN;
}
// check to see if we need to append the 80 clocks (i.e. this is the first transaction)
if (gSendInitClocks)
{
gSendInitClocks = FALSE;
cmdatRegister |= MMC_CMDAT_INIT;
fExtraDelay = TRUE;
}
if (gSD4BitMode)
{
cmdatRegister |= MMC_CMDAT_SD_4DAT;
}
// write the CMDAT register
g_pSDMMCRegisters->cmdat = cmdatRegister;
// set the the response timeout
g_pSDMMCRegisters->resto = 0x7F;
// set the data receive timeout
g_pSDMMCRegisters->rdto = SDH_DEFAULT_DATA_TIMEOUT_CLOCKS;
SDClockOn();
if( fExtraDelay )
{
PDD_SDStallExecute(500);
fExtraDelay = FALSE;
}
// Wait on response
while( !(g_pSDMMCRegisters->stat & (1<<13)) )
{
temp++;
if( g_pSDMMCRegisters->stat & ( (1<<5) | (1<<2) | (1<<1) ))
{
return FALSE;
}
}
// Grab the response
if (RESP_TYPE_NONE == resp)
{
pSrcPtr = NULL;
}
else if (RESP_TYPE_R2 == resp)
{
// 8 words - 128 bits
fifoCount = SDH_RESPONSE_FIFO_DEPTH;
pSrcPtr = ResponseBuffer + sizeof(ResponseBuffer);
}
else
{
// 3 WORDS - 48 bits
fifoCount = 3;
pSrcPtr = ResponseBuffer + 3*sizeof(WORD);
}
if (RESP_TYPE_NONE != resp && pSrcPtr!=NULL)
{
while (fifoCount--)
{
union
{
WORD wDataWord;
BYTE bDataByte[2];
} data;
data.wDataWord = (USHORT)(g_pSDMMCRegisters->res);
*(--pSrcPtr)=data.bDataByte[1];
*(--pSrcPtr)=data.bDataByte[0];
}
}
return TRUE;
}
BOOL PDD_SDReceiveData(UINT8* pBuffer)
{
UINT32 bytesRemaining = 0;
UINT32 bytesRead = 0;
UINT32 bytesToRead = 0;
UINT32 bytesReadThisIteration = 0;
volatile UCHAR *pMMC_RX_Fifo = (volatile UCHAR *)&(g_pSDMMCRegisters->rxfifo);
volatile DWORD *pMMC_RX_FifoDW = (volatile DWORD *)&(g_pSDMMCRegisters->rxfifo);
bytesRead = 0;
bytesRemaining = BLOCK_LEN;
while( bytesRead < BLOCK_LEN )
{
// Wait for RXFIFO_RD_REQ (since we are in PIO mode)
while( !(g_pSDMMCRegisters->ireg & (1<<5)) )
{
if( g_pSDMMCRegisters->ireg & ( (1<<10) |(1<<9) | (1<<8) ))
{
return FALSE;
}
}
bytesToRead = (bytesRemaining > 32) ? 32 : bytesRemaining;
bytesReadThisIteration = bytesToRead;
// empty the FIFO 32 bytes at a time
while (bytesToRead)
{
if( bytesToRead >= 4 )
{
union
{
BYTE dataByte[4];
DWORD dataLong;
} data;
register PBYTE pSrc = data.dataByte;
// read in the dword from the FIFO
data.dataLong = *pMMC_RX_FifoDW;
*(pBuffer++) = *(pSrc++);
*(pBuffer++) = *(pSrc++);
*(pBuffer++) = *(pSrc++);
*(pBuffer++) = *(pSrc++);
bytesToRead -= 4;
}
else while (bytesToRead)
{
// read in the byte from the FIFO
*(pBuffer++) = *pMMC_RX_Fifo;
bytesToRead--;
}
}
bytesRemaining -= bytesReadThisIteration;
bytesRead += bytesReadThisIteration;
}
return TRUE;
}
UINT32 PDD_SDGetResponse(SD_RESPONSE whichResp)
{
UINT32 response = 0;
UINT16 regVal = 0;
volatile UINT16 *pSD_Response_Fifo = (volatile UINT16 *)&(g_pSDMMCRegisters->res);
switch( whichResp ) {
case RCA_REGISTER:
// RCA is in bytes 3,4
response = (SD_CARD_RCA)ResponseBuffer[3];
response |= ((SD_CARD_RCA)ResponseBuffer[4]) << 8;
break;
case CARD_STATUS_REGISTER:
case OCR_REGISTER:
//32-bit responses
response = (DWORD)ResponseBuffer[1];
response |= ((DWORD)ResponseBuffer[2]) << 8;
response |= ((DWORD)ResponseBuffer[3]) << 16;
response |= ((DWORD)ResponseBuffer[4]) << 24;
break;
case SCR_REGISTER: //64-bit response
case CID_REGISTER: //128-bit responses
case CSD_REGISTER:
default:
response = 0; //Not implemented
}
return response;
}
VOID PDD_SDSetPDDCapabilities(PDD_IOCTL whichAbility, UINT32 Ability)
{
UINT32 Rate = Ability;
switch( whichAbility )
{
case SET_4BIT_MODE:
if( Ability )
{
gSD4BitMode = TRUE;
}
else
{
gSD4BitMode = FALSE;
}
break;
case SET_CLOCK_RATE:
SDSetRate(&Rate);
break;
}
}
UINT32 PDD_SDGetPDDCapabilities(PDD_IOCTL whichAbility)
{
switch( whichAbility )
{
case GET_SUPPORTED_OCR_SD:
return SD_VDD_WINDOW_3_2_TO_3_3;
default:
return 0;
}
}
VOID PDD_SDStallExecute(UINT32 waitMs) {
OALStall(waitMs*1000);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -