?? sdio.c
字號:
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2002 BSQUARE Corporation. All rights reserved.
//
// Module Name:
//
// SDIO.c
//
// Abstract:
//
// Au1100 SDIO controller driver implementation
//
// Notes:
//
///////////////////////////////////////////////////////////////////////////////
#include "sdcardddk.h"
#include "sdhcd.h"
#include "sdio.h"
#include <gpio.h>
// 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/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);
DbgPrintZo(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);
DbgPrintZo(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;
}
}
}
DbgPrintZo(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)
{
// 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+(pRequest->HCParam*pRequest->BlockSize),
pDmaBuffer,
pRequest->BlockSize);
} SD_RESTORE_PROC_PERMISSIONS();
}
///////////////////////////////////////////////////////////////////////////////
// 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:
///////////////////////////////////////////////////////////////////////////////
VOID CopyToDmaBuffer(PSD_BUS_REQUEST pRequest,
PULONG pDmaBuffer)
{
// 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+(pRequest->HCParam*pRequest->BlockSize),
pRequest->BlockSize);
} SD_RESTORE_PROC_PERMISSIONS();
}
///////////////////////////////////////////////////////////////////////////////
// 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) {
DbgPrintZo(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) {
DbgPrintZo(SDCARD_ZONE_ERROR,(TEXT("SDIO[%d]: Can't allocate Rx DMA Channel\r\n"),
pSlot->SlotNumber));
goto ErrorReturn;
}
pSlot->UsingDma = TRUE;
// Initialize channels
HalInitDmaChannel(pSlot->TxDmaChannel,
AuSdConfig[pSlot->SlotNumber].TxDmaDeviceId,
pSlot->DmaBufferSize,
TRUE);
// Initialize channels
HalInitDmaChannel(pSlot->RxDmaChannel,
AuSdConfig[pSlot->SlotNumber].RxDmaDeviceId,
pSlot->DmaBufferSize,
TRUE);
HalSetDMAForReceive(pSlot->RxDmaChannel);
// set up DMA interrupt
hwIntr = HalGetDMAHwIntr(pSlot->TxDmaChannel);
hwIntr |= (HalGetDMAHwIntr(pSlot->RxDmaChannel) << 8);
RETAILMSG(1,(TEXT("SDIO Hooking HWINTR %08X\r\n"),hwIntr));
pSlot->DmaSysIntr = InterruptConnect(Internal, 0, hwIntr, 0);
if (SYSINTR_NOP==pSlot->DmaSysIntr) {
DbgPrintZo(SDCARD_ZONE_ERROR,(TEXT("SDIO[%d]: Can't allocate DMA SYSINTR\r\n"),
pSlot->SlotNumber));
goto ErrorReturn;
}
RETAILMSG(1,(TEXT("DmaSysIntr = %X\r\n"),pSlot->DmaSysIntr));
// allocate the dma interrupt event
pSlot->hDmaInterruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == pSlot->hDmaInterruptEvent) {
DbgPrintZo(SDCARD_ZONE_ERROR,(TEXT("SDIO[%d]: Can't create DMA interrupt event\r\n"),
pSlot->SlotNumber));
goto ErrorReturn;
}
if (!InterruptInitialize(pSlot->DmaSysIntr,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -