sdcontrol.c

来自「该BSP是基于PXA270+WINCE的BSP」· C语言 代码 · 共 1,659 行 · 第 1/5 页

C
1,659
字号
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// Copyright (c) 2002 BSQUARE Corporation.  All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE
//
// Module Name:
//
//    SDControl.c
//
// Abstract:
//
//    PXA27X SDIO controller implementation
//
// Notes:
//
///////////////////////////////////////////////////////////////////////////////

//#define EXTENSIVE_DEBUGGING

#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <giisr.h>
#include "SDCardDDK.h"
#include "SDHCD.h"
#include "SD.h"

    // prototypes
PVOID VirtualAllocCopy(unsigned size,char *str,PVOID pVirtualAddress);
DWORD SDControllerIstThread(PSDH_HARDWARE_CONTEXT pHCDevice);
DWORD SDDMAIstThread(PSDH_HARDWARE_CONTEXT pHCDevice);
#ifdef DEBUG
void DumpRegisters(PSDH_HARDWARE_CONTEXT pController);
void DumpGPIORegisters(PSDH_HARDWARE_CONTEXT pController);
#endif
BOOL PrepareDmaTransfer( PSDH_HARDWARE_CONTEXT pController, PSD_BUS_REQUEST pRequest );

#ifdef DEBUG
#define HEXBUFSIZE 1024
char szHexBuf[HEXBUFSIZE];

#define TRANSFER_SIZE(pRequest)            ((pRequest)->BlockSize * (pRequest)->NumBlocks)

char* HexDisplay( BYTE *pBuffer, DWORD dwLength )
{
    DWORD dwTemp = 0;
	while( dwTemp < dwLength && (dwTemp < (HEXBUFSIZE / 2 - 1) ) )
	{
		szHexBuf[dwTemp*2] = pBuffer[dwTemp] / 16;
		szHexBuf[dwTemp*2+1] = pBuffer[dwTemp] % 16;
		
		if( szHexBuf[dwTemp*2] < 10 )
			szHexBuf[dwTemp*2] += '0';
		else
			szHexBuf[dwTemp*2] += 'a' - 10;

		if( szHexBuf[dwTemp*2+1] < 10 )
			szHexBuf[dwTemp*2+1] += '0';
		else
			szHexBuf[dwTemp*2+1] += 'a' - 10;

		dwTemp++;
	}
	szHexBuf[dwTemp*2] = 0;

    return szHexBuf;
}

void DumpHexDisplay( BYTE *pBuffer, DWORD dwLength )
{
    const int lsize = 64;
    char szBuffer[65];
    char* pszData;
    int l = 0;
    int total_l = dwLength / lsize;
    int r = dwLength % lsize;

    pszData = HexDisplay( pBuffer, dwLength );

    for( l = 0; l < total_l; l++ )
    {
        strncpy( szBuffer, pszData + l * lsize, lsize );
        szBuffer[lsize] = 0;
        DEBUGMSG( TRUE, (TEXT("%S\r\n"), szBuffer ) );
    }
    if( r )
    {
        strncpy( szBuffer, pszData + l * lsize, r );
        szBuffer[r] = 0;
        DEBUGMSG( TRUE, (TEXT("%S\r\n"), szBuffer ) );
    }
}

#endif

void WRITE_MMC_REGISTER_DWORD(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset, DWORD Value) 
{
    BYTE *pRegBaseAddr, *regAddr;
    volatile DWORD *pdwRegAddr;
    pRegBaseAddr = (BYTE*)(pHc->pSDMMCRegisters);
    regAddr = pRegBaseAddr + RegOffset;
    pdwRegAddr = (DWORD*)regAddr;
    *pdwRegAddr = Value;
}

DWORD READ_MMC_REGISTER_DWORD(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset)
{
    BYTE *pRegBaseAddr, *regAddr;
    volatile DWORD *pdwRegAddr;
    pRegBaseAddr = (BYTE*)(pHc->pSDMMCRegisters);
    regAddr = pRegBaseAddr + RegOffset;
    pdwRegAddr = (DWORD*)regAddr;
    return (*pdwRegAddr);
}

#define IS_PROGRAM_DONE(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_PROGRAM_DONE)
#define IS_TRANSFER_DONE(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_DATA_TRANSFER_DONE)

//#define RX_FIFO_FULL(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_RCV_FIFO_FULL)
//#define TX_FIFO_EMPTY(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_XMIT_FIFO_EMPTY)

#define TRANSFER_IS_WRITE(pRequest) ((SD_WRITE == (pRequest)->TransferClass))
#define TRANSFER_IS_READ(pRequest)  ((SD_READ == (pRequest)->TransferClass))

BOOL CLOCK_IS_ON(PSDH_HARDWARE_CONTEXT pHc)
{
    if( READ_MMC_REGISTER_DWORD( pHc, MMC_STAT ) & MMC_STAT_CLOCK_ENABLED )
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

void READ_MOD_WRITE_MMC_REGISTER_AND_OR(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset, DWORD AndValue, DWORD OrValue)
{
    DWORD regValue;
    regValue = READ_MMC_REGISTER_DWORD(pHc, RegOffset);
    regValue &= (AndValue);
    regValue |= (OrValue);
    DEBUGMSG(SDCARD_ZONE_INFO, (TEXT("SHCDriver: - Setting MMC Reg 0x%x to 0x%x\r\n"), RegOffset, regValue));
    WRITE_MMC_REGISTER_DWORD(pHc, RegOffset, regValue);
}

#define CLOCK_OFF_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_CLOCK_OFF_INT_MASKED)
 
    // macro to turn SDIO interrupts on
#define SDIO_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, ~MMC_IMASK_SDIO_INT_MASKED, 0)

    // macro to turn SDIO interrupts off
#define SDIO_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_SDIO_INT_MASKED)

    // macro to turn RX FIFO interrupts on
#define RX_FIFO_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, ~MMC_IMASK_RXFIFO_REQ_INT_MASKED, 0)

    // macro to turn RX FIFO interrupts off
#define RX_FIFO_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_RXFIFO_REQ_INT_MASKED)

    // macro to turn TX FIFO interrupts on
#define TX_FIFO_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK,~MMC_IMASK_TXFIFO_REQ_INT_MASKED, 0)

    // macro to turn TX FIFO interrupts off
#define TX_FIFO_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_TXFIFO_REQ_INT_MASKED)

#define TRANSFER_DONE_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, ~MMC_IMASK_DATA_TRAN_DONE_INT_MASKED, 0) 

#define TRANSFER_DONE_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_DATA_TRAN_DONE_INT_MASKED) 

#define END_CMD_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, ~MMC_IMASK_END_CMD_INT_MASKED, 0) 

#define END_CMD_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_END_CMD_INT_MASKED) 

#define PROGRAM_DONE_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, ~MMC_IMASK_PROG_DONE_INT_MASKED, 0) 

#define PROGRAM_DONE_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_PROG_DONE_INT_MASKED) 

#define PROGRAM_DATA_ERROR_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, ~MMC_IMASK_DATA_ERROR_INT_MASKED, 0) 

#define PROGRAM_DATA_ERROR_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_DATA_ERROR_INT_MASKED) 

#define PROGRAM_RESPONSE_ERROR_INTERRUPT_ON(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, ~MMC_IMASK_RESPONSE_ERROR_INT_MASKED, 0) 

#define PROGRAM_RESPONSE_ERROR_INTERRUPT_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_RESPONSE_ERROR_INT_MASKED) 

#define TX_BUFFER_PARTIAL_FULL(pHc) \
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_PRTBUF, MMC_PRTBUF_BUFFER_PARTIAL_FULL)

#define TX_BUFFER_PARTIAL_NOT_FULL(pHc) \
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_PRTBUF, 0)

#define ALL_INTERRUPTS_OFF(pHc) \
    READ_MOD_WRITE_MMC_REGISTER_AND_OR(pHc, MMC_IMASK, 0xffffffff, MMC_IMASK_ALL_INTERRUPTS_MASKED) 

    // 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)

///////////////////////////////////////////////////////////////////////////////
//  SDClockOff - turn off the MMC clock
//  Input:  pHc - hardware context
//  Output: 
//  Return:
//  Notes:  
//
///////////////////////////////////////////////////////////////////////////////
VOID SDClockOff(PSDH_HARDWARE_CONTEXT pHc)
{
        // check to see if the clock is on
    if (!CLOCK_IS_ON(pHc)) {
        return;
    }

    DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("SDClockOff - turning off clock \n")));
        // turn off the clock
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_STRPCL, MMC_STRPCL_STOP_CLOCK);
       
    while (CLOCK_IS_ON(pHc)) {
        // sit here and wait for the clock to turn off
        DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("Waiting for clock off\n")));
    }

    DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("SDClockOff - Clock is now off \n")));
}


///////////////////////////////////////////////////////////////////////////////
//  SDClockOn - turn on the MMC Clock
//  Input:  pHc - hardware context
//  Output: 
//  Return:
//  Notes:  
//          
//
///////////////////////////////////////////////////////////////////////////////
VOID SDClockOn(PSDH_HARDWARE_CONTEXT pHc)
{
        // turn on the clock
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_STRPCL, MMC_STRPCL_START_CLOCK);
}


///////////////////////////////////////////////////////////////////////////////
//  SDClockOn - turn on the MMC Clock
//  Input:  pHc - hardware context
//          pRate - pointer to desired clock rate in Hz
//  Output:
//  Return: 
//  Notes:  
//
///////////////////////////////////////////////////////////////////////////////
VOID SDSetRate(PSDH_HARDWARE_CONTEXT pHc, PDWORD pRate)
{
    ULONG ii;           // table index variable
    DWORD rate;
    BOOL fClockRunning;

    fClockRunning = CLOCK_IS_ON(pHc);
    SDClockOff(pHc);

    rate = *pRate;
    if( rate > pHc->dwMaximumSDClockFrequency )
        rate = pHc->dwMaximumSDClockFrequency;
   
        // 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;
            } 
        }
    }

    DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("SDClockOn - Requested Rate: %d, Setting clock rate to %d Hz \n"),
           *pRate, SDClockTable[ii].Frequency ));

        // return the actual fruency
    *pRate = SDClockTable[ii].Frequency;

         // set the clock rate
    WRITE_MMC_REGISTER_DWORD(pHc, MMC_CLKRT, SDClockTable[ii].ControlValue);
    pHc->dwSDClockFrequency = SDClockTable[ii].Frequency;
        
    if( fClockRunning )
    {

⌨️ 快捷键说明

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