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

📄 sdpdd.c

📁 Windows CE 6.0 BSP for VOIP sample phone. Intel PXA270 platform.
💻 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 + -