?? sdio.c
字號:
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2002,2004-2005 BSQUARE Corporation. All rights reserved.
//
// Module Name:
//
// SDIO.c
//
// Abstract:
//
// Au1100 SDIO controller driver implementation
//
// Notes:
//
///////////////////////////////////////////////////////////////////////////////
#include <windows.h> // For min() macro
#include <sdcardddk.h>
#include <sdhcd.h>
#include "sdio.h"
#include "gpio.h"
typedef struct {
ULONG BlocksCopied;
ULONG BytesCopied;
ULONG BuffersOutstanding;
} HC_PARAMS, *PHC_PARAMS;
static HC_PARAMS HCParams;
// clock rate table structure
typedef struct _CLOCK_RATE_ENTRY {
DWORD Frequency;
USHORT ControlValue;
} CLOCK_RATE_ENTRY, *PCLOCK_RATE_ENTRY;
// lookup table of some of the more useful SD clock frequencies
CLOCK_RATE_ENTRY SDIOClockTable[] =
{ // FREQ Divisor Rate assuming 50MHz MCLK
{CONTROLLER_CLOCK_FREQUENCY/512, 511}, // 98 Khz
{CONTROLLER_CLOCK_FREQUENCY/256, 255}, // 195 Khz
{CONTROLLER_CLOCK_FREQUENCY/128, 127}, // 391 Khz
{CONTROLLER_CLOCK_FREQUENCY/64, 63}, // 781 Khz
{CONTROLLER_CLOCK_FREQUENCY/32, 31}, // 1.5 Mhz
{CONTROLLER_CLOCK_FREQUENCY/16, 15}, // 3.13 Mhz
{CONTROLLER_CLOCK_FREQUENCY/8, 7}, // 6.25 Mhz
{CONTROLLER_CLOCK_FREQUENCY/4, 3}, // 12.5 Mhz
{CONTROLLER_CLOCK_FREQUENCY/3, 2}, // 16.6 Mhz
{CONTROLLER_CLOCK_FREQUENCY/2, 1}, // 25 Mhz
};
#define NUM_CLOCK_ENTRIES sizeof(SDIOClockTable)/sizeof(CLOCK_RATE_ENTRY)
// structure containing configuration information for each slot
typedef struct {
ULONG SDPhysAddr;
ULONG TxDmaDeviceId;
ULONG RxDmaDeviceId;
} AUSDIO_CONFIG;
AUSDIO_CONFIG AuSdConfig[] = {
{ SD0_PHYS_ADDR, DMA_SD0_TX, DMA_SD0_RX },
{ SD1_PHYS_ADDR, DMA_SD1_TX, DMA_SD1_RX }
};
///////////////////////////////////////////////////////////////////////////////
// ResetSlot - reset the slot to its initial state
// Input: pSlot - slot context
// Output:
// Return:
///////////////////////////////////////////////////////////////////////////////
VOID ResetSlot(PSDIO_SLOT pSlot, BOOL IsInitPath)
{
ULONG divisor = 0;
ULONG config2 = 0;
if (!IsInitPath)
{
config2 = READ_REGISTER_ULONG((PULONG)&pSlot->pSD->config2);
divisor = READ_REGISTER_ULONG((PULONG)&pSlot->pSD->config);
divisor &= SD_CONFIG_DIV;
}
// reset the controller
WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->enable, 0);
WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->enable, SD_ENABLE_CE);
WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->enable, SD_ENABLE_R | SD_ENABLE_CE);
// enable the state machines
WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->config2, config2 | SD_CONFIG2_EN );
// set the timeout to max
WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->timeout, SD_TIMEOUT_MAX );
// write clock
WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->config, divisor | SD_CONFIG_DE);
// Disable all interrupts
SD_INTERRUPTS_DISABLE(pSlot,0xFFFFFFFF);
// Clear interrupt status
SD_INTERRUPTS_CLEAR(pSlot,0xFFFFFFFF);
// Enable master inerrupt
SD_INTERRUPTS_ENABLE(pSlot, SD_Int_Master );
}
///////////////////////////////////////////////////////////////////////////////
// DumpSlot - dump the states of the slot
// Input: pSlot - slot context
// Output:
// Return:
///////////////////////////////////////////////////////////////////////////////
VOID DumpSlot( PSDIO_SLOT pSlot )
{
RETAILMSG(1,(TEXT("SDIO SLOT %d\r\n"),pSlot->SlotNumber));
RETAILMSG(1,(TEXT("SD_CONFIG = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->config)));
RETAILMSG(1,(TEXT("SD_ENABLE = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->enable)));
RETAILMSG(1,(TEXT("SD_CONFIG2 = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->config2)));
RETAILMSG(1,(TEXT("SD_BLKSIZE = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->blksize)));
RETAILMSG(1,(TEXT("SD_STATUS = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->status)));
RETAILMSG(1,(TEXT("SD_DEBUG = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->debug)));
RETAILMSG(1,(TEXT("SD_CMD = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->cmd)));
RETAILMSG(1,(TEXT("SD_CMDARG = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->cmdarg)));
RETAILMSG(1,(TEXT("SD_TIMEOUT = 0x%08X\r\n"),READ_REGISTER_ULONG((PULONG)&pSlot->pSD->timeout)));
if (NULL!=pSlot->pCurrentRequest) {
RETAILMSG(1, (TEXT("pCurrentRequest->CommandCode = %d\r\n"),pSlot->pCurrentRequest->CommandCode));
RETAILMSG(1, (TEXT("pCurrentRequest->NumBlocks = %d\r\n"),pSlot->pCurrentRequest->NumBlocks));
RETAILMSG(1, (TEXT("pCurrentRequest->BlockSize = %d\r\n"),pSlot->pCurrentRequest->BlockSize));
RETAILMSG(1, (TEXT("pCurrentRequest->HCParam = %d\r\n"),pSlot->pCurrentRequest->HCParam));
}
RETAILMSG(1,(TEXT("InterruptMask = 0x%08X\r\n"),pSlot->InterruptMask));
RETAILMSG(1,(TEXT("CardPresent = %d\r\n"),pSlot->CardPresent));
RETAILMSG(1,(TEXT("CheckSlotOnStartUp = %d\r\n"),pSlot->CheckSlotOnStartUp));
RETAILMSG(1,(TEXT("CardInitialised = %d\r\n"),pSlot->CardInitialised));
}
///////////////////////////////////////////////////////////////////////////////
// DumpController - dump the states of the controller
// Input: pController - controller context
// Output:
// Return:
///////////////////////////////////////////////////////////////////////////////
VOID DumpController( PSDIO_HW_CONTEXT pController )
{
int i;
for (i=0;i<SDIOPlatNumSlots();i++) {
DumpSlot(&pController->Slots[i]);
}
}
///////////////////////////////////////////////////////////////////////////////
// SDIOClockOff - turn off the SD clock
// Input: pSlot - slot context
// Output:
// Return:
// Notes: Currently simply leave the clock along for now.
///////////////////////////////////////////////////////////////////////////////
VOID SDIOClockOff(PSDIO_SLOT pSlot)
{
ULONG tmp;
// turn off the clock
tmp = READ_REGISTER_ULONG((PULONG)&pSlot->pSD->enable);
tmp &= ~SD_ENABLE_CE;
// WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->enable,tmp);
DEBUGMSG(SDIO_CLOCK_ZONE, (TEXT("SDIOClockOff - Clock is now off \n")));
}
///////////////////////////////////////////////////////////////////////////////
// SDIOClockOn - turn on the MMC Clock
// Input: pSlot - slot context
// Output:
// Return:
// Notes:
///////////////////////////////////////////////////////////////////////////////
VOID SDIOClockOn(PSDIO_SLOT pSlot)
{
ULONG tmp;
// turn on the clock
tmp = READ_REGISTER_ULONG((PULONG)&pSlot->pSD->enable);
tmp |= SD_ENABLE_CE;
WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->enable,tmp);
DEBUGMSG(SDIO_CLOCK_ZONE, (TEXT("SDIOClockOn - Clock is now on \n")));
}
///////////////////////////////////////////////////////////////////////////////
// SDIOSetRate - sets rate of SD Clock
// Input: pSlot - slot context
// pRate - desired clock rate in Hz
// Output: pRate - the clock rate now in use
// Return:
// Notes: Divisor could easily be calculated
///////////////////////////////////////////////////////////////////////////////
VOID SDIOSetRate(PSDIO_SLOT pSlot, PDWORD pRate)
{
ULONG ii; // table index variable
ULONG regValue; // temp register value
// check to see if the rate is below the first entry in the table
if (*pRate <= SDIOClockTable[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 ((*pRate >= SDIOClockTable[ii].Frequency) &&
(*pRate < SDIOClockTable[ii+1].Frequency)) {
break;
}
}
}
DEBUGMSG(SDIO_CLOCK_ZONE, (TEXT("SDIOSetRate - Requested Rate: %d, Setting clock rate to %d Hz \n"),
*pRate, SDIOClockTable[ii].Frequency ));
// return the actual frequency
*pRate = SDIOClockTable[ii].Frequency;
// update the divisor setting
regValue = READ_REGISTER_ULONG((PULONG)&pSlot->pSD->config );
// clear old divisor
regValue &= ~SD_CONFIG_DIV;
// set new divisot
regValue |= SDIOClockTable[ii].ControlValue;
regValue |= SD_CONFIG_DE;
// write new value back
WRITE_REGISTER_ULONG((PULONG)&pSlot->pSD->config, regValue );
}
#ifdef USE_DMA
///////////////////////////////////////////////////////////////////////////////
// CopyFromDmaBuffer - Copy data from a DMA buffer into a requests data buffer
// Input: pRequest - the request that this data belongs to
// pDmaBuffer - which buffer to copy from
// Output:
// Return:
// Notes:
///////////////////////////////////////////////////////////////////////////////
VOID CopyFromDmaBuffer(PSD_BUS_REQUEST pRequest,
PULONG pDmaBuffer)
{
ULONG blocksToCopy;
ULONG blocksRemaining;
blocksRemaining = pRequest->NumBlocks - ((PHC_PARAMS)pRequest->HCParam)->BlocksCopied;
if (blocksRemaining > (DMA_BUFFER_SIZE / pRequest->BlockSize)) {
blocksToCopy = (DMA_BUFFER_SIZE / pRequest->BlockSize);
} else {
blocksToCopy = blocksRemaining;
}
// we are touching the block buffer, set the process permissions
SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {
// safe copy data into block buffer
SDPerformSafeCopy(pRequest->pBlockBuffer+(((PHC_PARAMS)pRequest->HCParam)->BlocksCopied*pRequest->BlockSize),
pDmaBuffer,
pRequest->BlockSize * blocksToCopy);
} SD_RESTORE_PROC_PERMISSIONS();
((PHC_PARAMS)pRequest->HCParam)->BlocksCopied += blocksToCopy;
((PHC_PARAMS)pRequest->HCParam)->BuffersOutstanding--;
}
///////////////////////////////////////////////////////////////////////////////
// CopyToDmaBuffer - Copy data to a DMA buffer from a requests data buffer
// Input: pRequest - the request that this data belongs to
// pDmaBuffer - which buffer to copy to
// Output:
// Return:
// Notes:
///////////////////////////////////////////////////////////////////////////////
ULONG CopyToDmaBuffer(PSD_BUS_REQUEST pRequest,
PULONG pDmaBuffer)
{
ULONG blocksToCopy;
ULONG blocksRemaining;
blocksRemaining = pRequest->NumBlocks - ((PHC_PARAMS)pRequest->HCParam)->BlocksCopied;
if (blocksRemaining > (DMA_BUFFER_SIZE / pRequest->BlockSize)) {
blocksToCopy = (DMA_BUFFER_SIZE / pRequest->BlockSize);
} else {
blocksToCopy = blocksRemaining;
}
// we are touching the block buffer, set the process permissions
SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {
// safe copy data into block buffer
SDPerformSafeCopy(pDmaBuffer,
pRequest->pBlockBuffer+(((PHC_PARAMS)pRequest->HCParam)->BlocksCopied*pRequest->BlockSize),
pRequest->BlockSize * blocksToCopy);
} SD_RESTORE_PROC_PERMISSIONS();
((PHC_PARAMS)pRequest->HCParam)->BlocksCopied += blocksToCopy;
// Incrementing count of outstanding blocks
// IST will decrement this when a block has been transmitted
((PHC_PARAMS)pRequest->HCParam)->BuffersOutstanding++;
return (blocksToCopy*pRequest->BlockSize);
}
///////////////////////////////////////////////////////////////////////////////
// SDIOInitializeDMA - Initialize DMA resources for an SD slot
// Input: pSlot - slot context
// Output:
// Return:
// Notes:
///////////////////////////////////////////////////////////////////////////////
BOOL SDIOInitializeDMA(PSDIO_SLOT pSlot)
{
ULONG hwIntr;
DWORD threadID; // thread ID
// Allocate Tx DMA Channel
pSlot->TxDmaChannel = HalAllocateDMAChannel();
if (pSlot->TxDmaChannel==NULL) {
DEBUGMSG(SDCARD_ZONE_ERROR,(TEXT("SDIO[%d]: Can't allocate Tx DMA Channel\r\n"),
pSlot->SlotNumber));
goto ErrorReturn;
}
// Allocate Rx DMA Channel
pSlot->RxDmaChannel = HalAllocateDMAChannel();
if (pSlot->RxDmaChannel==NULL) {
DEBUGMSG(SDCARD_ZONE_ERROR,(TEXT("SDIO[%d]: Can't allocate Rx DMA Channel\r\n"),
pSlot->SlotNumber));
goto ErrorReturn;
}
pSlot->UsingDma = TRUE;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -