first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,25 @@
|
||||
# Copyright (C) 2008 Apple Computer, Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Computer, Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Computer, Inc.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
ifeq ($(APPLICATION),EmbeddedIOP)
|
||||
|
||||
GLOBAL_INCLUDES += \
|
||||
$(LOCAL_DIR)
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/sdiodrv_config.o \
|
||||
$(LOCAL_DIR)/sdiodrv_command.o \
|
||||
$(LOCAL_DIR)/sdiodrv_transfer.o \
|
||||
$(LOCAL_DIR)/sdiocommon/sdhc_debug.o \
|
||||
$(LOCAL_DIR)/sdiocommon/sdhc_registers.o \
|
||||
$(LOCAL_DIR)/sdiocommon/sdio_cmdprop.o
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include "sdhc_debug.h"
|
||||
|
||||
#ifdef PLATFORM_VARIANT_IOP
|
||||
#include <lib/libc.h>
|
||||
#else
|
||||
#include <libkern/libkern.h>
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
sdhc_dumpRegisterFile(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
printf("SDHC @ %p, size = %lu\n", sdhc, sizeof(*sdhc));
|
||||
printf(" SD Command Generation:\n");
|
||||
printf(" sdmaSystemAddr = 0x%08X\n", (uint32_t)sdhc->sdmaSystemAddr);
|
||||
printf(" blockSize = 0x%04X\n", sdhc->blockSize);
|
||||
printf(" blockCount = 0x%04X\n", sdhc->blockCount);
|
||||
printf(" argument = 0x%08X\n", (uint32_t)sdhc->argument);
|
||||
printf(" transferMode = 0x%04X\n", sdhc->transferMode);
|
||||
printf(" command = 0x%04X\n", sdhc->command);
|
||||
|
||||
printf(" Response:\n");
|
||||
for(unsigned i=0; i<4; i++) {
|
||||
printf(" response[%u] = 0x%08X\n", i, (uint32_t)sdhc->response[i]);
|
||||
}
|
||||
|
||||
printf(" Buffer Data Port:\n");
|
||||
printf(" bufferDataPort = 0x%08X\n", (uint32_t)sdhc->bufferDataPort);
|
||||
|
||||
printf(" Host Controls:\n");
|
||||
printf(" presentState = 0x%08X\n", (uint32_t)sdhc->presentState);
|
||||
printf(" hostControl = 0x%02X\n", sdhc->hostControl);
|
||||
printf(" powerControl = 0x%02X\n", sdhc->powerControl);
|
||||
printf(" blockGapControl = 0x%02X\n", sdhc->blockGapControl);
|
||||
printf(" wakeupControl = 0x%02X\n", sdhc->wakeupControl);
|
||||
printf(" clockControl = 0x%04X\n", sdhc->clockControl);
|
||||
printf(" timeoutControl = 0x%02X\n", sdhc->timeoutControl);
|
||||
printf(" softwareReset = 0x%02X\n", sdhc->softwareReset);
|
||||
|
||||
printf(" Interrupt Controls:\n");
|
||||
printf(" normalInterruptStatus = 0x%04X\n", sdhc->normalInterruptStatus);
|
||||
printf(" errorInterruptStatus = 0x%04X\n", sdhc->errorInterruptStatus);
|
||||
printf(" normalInterruptStatusEnable = 0x%04X\n", sdhc->normalInterruptStatusEnable);
|
||||
printf(" errorInterruptStatusEnable = 0x%04X\n", sdhc->errorInterruptStatusEnable);
|
||||
printf(" normalInterruptSignalEnable = 0x%04X\n", sdhc->normalInterruptSignalEnable);
|
||||
printf(" errorInterruptSignalEnable = 0x%04X\n", sdhc->errorInterruptSignalEnable);
|
||||
printf(" autoCmd12ErrorStatus = 0x%04X\n", sdhc->autoCmd12ErrorStatus);
|
||||
|
||||
printf(" Capabilities:\n");
|
||||
printf(" capabilities = 0x%016llX\n", sdhc->capabilities);
|
||||
printf(" maxCurrentCapabilities = 0x%016llX\n", sdhc->maxCurrentCapabilities);
|
||||
|
||||
printf(" Force Event:\n");
|
||||
printf(" forceEventAutoCmd12ErrorStatus = 0x%04X\n", sdhc->forceEventAutoCmd12ErrorStatus);
|
||||
printf(" forceEventErrorInterruptStatus = 0x%04X\n", sdhc->forceEventErrorInterruptStatus);
|
||||
|
||||
printf(" ADMA:\n");
|
||||
printf(" admaErrorStatus = 0x%02X\n", sdhc->admaErrorStatus);
|
||||
printf(" admaSystemAddr = 0x%016llX\n", sdhc->admaSystemAddr);
|
||||
|
||||
printf(" Common:\n");
|
||||
printf(" slotInterruptStatus = 0x%04X\n", sdhc->slotInterruptStatus);
|
||||
printf(" hostControllerVersion = 0x%04X\n", sdhc->hostControllerVersion);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDHC_DEBUG_H
|
||||
#define _SDHC_DEBUG_H
|
||||
|
||||
|
||||
#ifdef PLATFORM_VARIANT_IOP
|
||||
#include <sdiocommon/sdhc_registers.h>
|
||||
#else
|
||||
#include <IOKit/sdio/sdhc_registers.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
void sdhc_dumpRegisterFile(const SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SDHC_DEBUG_H */
|
||||
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "sdhc_registers.h"
|
||||
|
||||
|
||||
// TODO: Endianness
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Macros
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Capabilities
|
||||
|
||||
enum SDHCCapabilitiesFieldOffset
|
||||
{
|
||||
kSDHCCapabilityBaseClockRateOffset = 8,
|
||||
kSDHCCapabilityMaxBlockLengthOffset = 16,
|
||||
kSDHCCapabilityHighSpeedSupportOffset = 21,
|
||||
kSDHCCapabilitySuspendResumeSupportOffset = 23
|
||||
};
|
||||
|
||||
enum SDHCCapabilitiesField
|
||||
{
|
||||
kSDHCCapabilityBaseClockRate = (0x3F << kSDHCCapabilityBaseClockRateOffset),
|
||||
kSDHCCapabilityMaxBlockLength = (0x3 << kSDHCCapabilityMaxBlockLengthOffset),
|
||||
kSDHCCapabilityHighSpeedSupport = (1 << kSDHCCapabilityHighSpeedSupportOffset),
|
||||
kSDHCCapabilitySuspendResumeSupport = (1 << kSDHCCapabilitySuspendResumeSupportOffset),
|
||||
};
|
||||
|
||||
|
||||
|
||||
UInt16
|
||||
sdhc_getMaxBlockLength(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
static UInt16 mapBlkLenCapToLen[] = {512, 1024, 2048, 0};
|
||||
|
||||
UInt8 cap = (sdhc->capabilities & kSDHCCapabilityMaxBlockLength) >> kSDHCCapabilityMaxBlockLengthOffset;
|
||||
|
||||
return mapBlkLenCapToLen[cap];
|
||||
}
|
||||
|
||||
UInt32
|
||||
sdhc_getBaseClockFrequencyHz(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
UInt32 rateMHz = (sdhc->capabilities & kSDHCCapabilityBaseClockRate) >> kSDHCCapabilityBaseClockRateOffset;
|
||||
return rateMHz * 1000000;
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isSuspendResumeSupported(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->capabilities & kSDHCCapabilitySuspendResumeSupport;
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isHighSpeedSupported(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->capabilities & kSDHCCapabilityHighSpeedSupport;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Present State
|
||||
|
||||
enum PresentStateFieldOffsets
|
||||
{
|
||||
kCmdInhibitOffset = 0,
|
||||
kDataInhibitOffset = 1,
|
||||
};
|
||||
|
||||
enum PresentStateField
|
||||
{
|
||||
kCmdInhibit = (1 << kCmdInhibitOffset),
|
||||
kDataInhibit = (1 << kDataInhibitOffset),
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
sdhc_isCommandInhibitedOnCmd(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->presentState & kCmdInhibit;
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isCommandInhibitedOnData(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->presentState & kDataInhibit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Clocks
|
||||
|
||||
|
||||
#define kMaxClockDivisor (256)
|
||||
|
||||
enum ClkControlFieldOffsets
|
||||
{
|
||||
kInternalClkEnableOffset = 0,
|
||||
kInternalClkStableOffset = 1,
|
||||
kSDClkEnableOffset = 2,
|
||||
kSDClkFrequencySelectOffset = 8
|
||||
};
|
||||
|
||||
enum ClkControlFields
|
||||
{
|
||||
kInternalClkEnable = (1 << kInternalClkEnableOffset),
|
||||
kInternalClkStable = (1 << kInternalClkStableOffset),
|
||||
kSDClkEnable = (1 << kSDClkEnableOffset),
|
||||
kSDClkFrequencySelect = (0xFF << kSDClkFrequencySelectOffset)
|
||||
};
|
||||
|
||||
UInt32
|
||||
sdhc_setClockDividerRate(SDHCRegisters_t *sdhc, UInt32 targetSDClkRateHz, UInt32 inputClkRateHz)
|
||||
{
|
||||
UInt16 divisor = 1;
|
||||
|
||||
while(inputClkRateHz / divisor > targetSDClkRateHz) {
|
||||
divisor *= 2;
|
||||
}
|
||||
|
||||
divisor = min(divisor, kMaxClockDivisor);
|
||||
|
||||
sdhc_setClockDivider(sdhc, divisor);
|
||||
|
||||
return inputClkRateHz / divisor;
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_setClockDivider(SDHCRegisters_t *sdhc, UInt16 divisor)
|
||||
{
|
||||
divisor >>= 1; // divisor is offset, 0x00 == clk / 1
|
||||
divisor <<= kSDClkFrequencySelectOffset; // shift to correct offset
|
||||
|
||||
sdhc->clockControl &= ~kSDClkFrequencySelect;
|
||||
|
||||
// Note: must enable internal clock here or SDIO block will lock up
|
||||
sdhc->clockControl |= (divisor | kInternalClkEnable);
|
||||
}
|
||||
|
||||
UInt16
|
||||
sdhc_getClockDivider(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
UInt16 clkControl = sdhc->clockControl & kSDClkFrequencySelect;
|
||||
|
||||
clkControl >>= kSDClkFrequencySelectOffset; // shift to correct offset
|
||||
|
||||
// divisor is offset, 0x00 == clk / 1
|
||||
clkControl <<= 1;
|
||||
if(0 == clkControl) {
|
||||
clkControl = 1;
|
||||
}
|
||||
|
||||
return clkControl;
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_enableInternalClock(SDHCRegisters_t *sdhc, bool enable)
|
||||
{
|
||||
UInt16 clkControl = sdhc->clockControl;
|
||||
|
||||
if(enable) {
|
||||
clkControl |= kInternalClkEnable;
|
||||
} else {
|
||||
clkControl &= ~kInternalClkEnable;
|
||||
}
|
||||
|
||||
sdhc->clockControl = clkControl;
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isInternalClockStable(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->clockControl & kInternalClkStable;
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_enableSDClock(SDHCRegisters_t *sdhc, bool enable)
|
||||
{
|
||||
UInt16 clkControl = sdhc->clockControl;
|
||||
|
||||
if(enable) {
|
||||
clkControl |= kSDClkEnable;
|
||||
} else {
|
||||
clkControl &= ~kSDClkEnable;
|
||||
}
|
||||
|
||||
sdhc->clockControl = clkControl;
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isSDClockEnabled(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->clockControl & kSDClkEnable;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Block Size
|
||||
|
||||
|
||||
enum SDHCBlockSizeOffset
|
||||
{
|
||||
kSDHCTransferSizeOffset = 0,
|
||||
kSDHCHostSDMABufferSizeOffset = 12,
|
||||
kSDHCTransferSizeHighOffset = 15,
|
||||
};
|
||||
|
||||
enum SDHCBlockSizeMask
|
||||
{
|
||||
kSDHCTransferSize = (0xFFF << kSDHCTransferSizeOffset),
|
||||
kSDHCHostSDMABufferSize = (0x7 << kSDHCTransferSizeOffset),
|
||||
kSDHCTransferSizeHigh = (1 << kSDHCTransferSizeHighOffset),
|
||||
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
sdhc_setBlockSize(SDHCRegisters_t *sdhc, UInt16 size)
|
||||
{
|
||||
UInt16 blockSize = sdhc->blockSize & ~(kSDHCTransferSizeHigh | kSDHCTransferSize);
|
||||
|
||||
|
||||
blockSize |= size & kSDHCTransferSize;
|
||||
|
||||
// High bit
|
||||
blockSize |= (size & (1 << kSDHCHostSDMABufferSizeOffset))
|
||||
<< (kSDHCTransferSizeHighOffset - kSDHCHostSDMABufferSizeOffset);
|
||||
|
||||
sdhc->blockSize = blockSize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Commands
|
||||
|
||||
void
|
||||
sdhc_copyCommandResponse(const SDHCRegisters_t *sdhc, struct SDIOCommandResponse *response)
|
||||
{
|
||||
for(UInt16 i=0; i < 4; ++i) {
|
||||
response->response[i] = sdhc->response[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Command State
|
||||
|
||||
|
||||
enum NormalIntFieldOffsets
|
||||
{
|
||||
kCmdCompleteIntOffset = 0,
|
||||
kTransferCompleteIntOffset = 1,
|
||||
kBlockGapIntOffset = 2,
|
||||
kDMAIntOffset = 3,
|
||||
kBufferWriteReadyIntOffset = 4,
|
||||
kBufferReadReadyIntOffset = 5,
|
||||
kCardInsertionIntOffset = 6,
|
||||
kCardRemovalIntOffset = 7,
|
||||
kCardIntOffset = 8,
|
||||
|
||||
kErrorIntOffset = 15
|
||||
};
|
||||
|
||||
enum NormalIntFields
|
||||
{
|
||||
kCmdCompleteInt = (1 << kCmdCompleteIntOffset),
|
||||
kTransferCompleteInt = (1 << kTransferCompleteIntOffset),
|
||||
kBlockGapInt = (1 << kBlockGapIntOffset),
|
||||
kDMAInt = (1 << kDMAIntOffset),
|
||||
kBufferWriteReadyInt = (1 << kBufferWriteReadyIntOffset),
|
||||
kBufferReadReadyInt = (1 << kBufferReadReadyIntOffset),
|
||||
kCardInsertionInt = (1 << kCardInsertionIntOffset),
|
||||
kCardRemovalInt = (1 << kCardRemovalIntOffset),
|
||||
kCardInt = (1 << kCardIntOffset),
|
||||
|
||||
kErrorInt = (1 << kErrorIntOffset),
|
||||
};
|
||||
|
||||
enum ErrorIntFieldOffsets
|
||||
{
|
||||
kCmdTimeoutErrorIntOffset = 0,
|
||||
kCmdCRCErrorIntOffset = 1,
|
||||
kCmdEndBitErrorIntOffset = 2,
|
||||
kCmdIndexErrorIntOffset = 3,
|
||||
kDataTimeoutErrorIntOffset = 4,
|
||||
kDataCRCErrorIntOffset = 5,
|
||||
kDataEndBitErrorIntOffset = 6,
|
||||
kCurrentLimitErrorIntOffset = 7,
|
||||
kAutoCmd12ErrorIntOffset = 8,
|
||||
kADMAErrorIntOffset = 9
|
||||
};
|
||||
|
||||
enum ErrorIntFields
|
||||
{
|
||||
kCmdTimeoutErrorInt = (1 << kCmdTimeoutErrorIntOffset),
|
||||
kCmdCRCErrorInt = (1 << kCmdCRCErrorIntOffset),
|
||||
kCmdEndBitErrorInt = (1 << kCmdEndBitErrorIntOffset),
|
||||
kCmdIndexErrorInt = (1 << kCmdIndexErrorIntOffset),
|
||||
kDataTimeoutErrorInt = (1 << kDataTimeoutErrorIntOffset),
|
||||
kDataCRCErrorInt = (1 << kDataCRCErrorIntOffset),
|
||||
kDataEndBitErrorInt = (1 << kDataEndBitErrorIntOffset),
|
||||
kCurrentLimitErrorInt = (1 << kCurrentLimitErrorIntOffset),
|
||||
kAutoCmd12ErrorInt = (1 << kAutoCmd12ErrorIntOffset),
|
||||
kADMAErrorInt = (1 << kADMAErrorIntOffset)
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
sdhc_enableCommandStatus(SDHCRegisters_t *sdhc, bool enable)
|
||||
{
|
||||
if(enable) {
|
||||
sdhc->normalInterruptStatusEnable |= kCmdCompleteInt;
|
||||
sdhc->errorInterruptStatusEnable |= (kCmdIndexErrorInt | kCmdEndBitErrorInt | kCmdCRCErrorInt | kCmdTimeoutErrorInt);
|
||||
} else {
|
||||
sdhc->normalInterruptStatusEnable &= ~kCmdCompleteInt;
|
||||
sdhc->errorInterruptStatusEnable &= ~(kCmdIndexErrorInt | kCmdEndBitErrorInt | kCmdCRCErrorInt | kCmdTimeoutErrorInt);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isCommandComplete(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return (sdhc->normalInterruptStatus & kCmdCompleteInt)
|
||||
|| (sdhc->errorInterruptStatus
|
||||
& (kCmdIndexErrorInt | kCmdEndBitErrorInt | kCmdCRCErrorInt | kCmdTimeoutErrorInt));
|
||||
}
|
||||
|
||||
SDIOReturn_t
|
||||
sdhc_getCommandStatus(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
const UInt16 state = kCmdTimeoutErrorInt | kCmdCRCErrorInt;
|
||||
const UInt16 errorStatus = sdhc->errorInterruptStatus;
|
||||
|
||||
if((errorStatus & state) == state) {
|
||||
return kSDIOReturnCmdLineConflict;
|
||||
} else if(errorStatus & kCmdTimeoutErrorInt) {
|
||||
return kSDIOReturnCmdTimeout;
|
||||
} else if(errorStatus & kCmdCRCErrorInt) {
|
||||
return kSDIOReturnCmdCRCError;
|
||||
} else if(errorStatus & kCmdEndBitErrorInt) {
|
||||
return kSDIOReturnCmdEndBitError;
|
||||
} else if(errorStatus & kCmdIndexErrorInt) {
|
||||
return kSDIOReturnCmdIndexError;
|
||||
} else {
|
||||
return kSDIOReturnSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_clearCommandStatus(SDHCRegisters_t *sdhc)
|
||||
{
|
||||
sdhc->normalInterruptStatus = kCmdCompleteInt;
|
||||
sdhc->errorInterruptStatus = (kCmdIndexErrorInt | kCmdEndBitErrorInt | kCmdCRCErrorInt | kCmdTimeoutErrorInt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Transfer State
|
||||
|
||||
void
|
||||
sdhc_enableTransferStatus(SDHCRegisters_t *sdhc, bool enable)
|
||||
{
|
||||
if(enable) {
|
||||
sdhc->normalInterruptStatusEnable |= kTransferCompleteInt;
|
||||
sdhc->errorInterruptStatusEnable |= (kDataTimeoutErrorInt | kDataCRCErrorInt | kDataEndBitErrorInt);
|
||||
} else {
|
||||
sdhc->normalInterruptStatusEnable &= ~kTransferCompleteInt;
|
||||
sdhc->errorInterruptStatusEnable &= ~(kDataTimeoutErrorInt | kDataCRCErrorInt | kDataEndBitErrorInt);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isTransferComplete(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return (sdhc->normalInterruptStatus & kTransferCompleteInt)
|
||||
|| (sdhc->errorInterruptStatus
|
||||
& (kDataTimeoutErrorInt | kDataCRCErrorInt | kDataEndBitErrorInt));
|
||||
}
|
||||
|
||||
SDIOReturn_t
|
||||
sdhc_getTransferStatus(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
const UInt16 errorStatus = sdhc->errorInterruptStatus;
|
||||
|
||||
if((errorStatus & kDataTimeoutErrorInt)
|
||||
&& !(sdhc->normalInterruptStatus & kTransferCompleteInt)) {
|
||||
return kSDIOReturnDataTimeout;
|
||||
} else if(errorStatus & kDataCRCErrorInt) {
|
||||
return kSDIOReturnDataCRCError;
|
||||
} else if(errorStatus & kDataEndBitErrorInt) {
|
||||
return kSDIOReturnDataEndBitError;
|
||||
} else {
|
||||
return kSDIOReturnSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_clearTransferStatus(SDHCRegisters_t *sdhc)
|
||||
{
|
||||
sdhc->normalInterruptStatus = kTransferCompleteInt;
|
||||
sdhc->errorInterruptStatus = (kDataTimeoutErrorInt | kDataCRCErrorInt | kDataEndBitErrorInt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PIO
|
||||
|
||||
bool
|
||||
sdhc_isBufferReadReady(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->normalInterruptStatus & kBufferReadReadyInt;
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_enableBufferReadReady(SDHCRegisters_t *sdhc, bool enable)
|
||||
{
|
||||
if(enable) {
|
||||
sdhc->normalInterruptStatusEnable |= kBufferReadReadyInt;
|
||||
} else {
|
||||
sdhc->normalInterruptStatusEnable &= ~kBufferReadReadyInt;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_clearBufferReadReady(SDHCRegisters_t *sdhc)
|
||||
{
|
||||
sdhc->normalInterruptStatus = kBufferReadReadyInt;
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isBufferWriteReady(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->normalInterruptStatus & kBufferWriteReadyInt;
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_enableBufferWriteReady(SDHCRegisters_t *sdhc, bool enable)
|
||||
{
|
||||
if(enable) {
|
||||
sdhc->normalInterruptStatusEnable |= kBufferWriteReadyInt;
|
||||
} else {
|
||||
sdhc->normalInterruptStatusEnable &= ~kBufferWriteReadyInt;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_clearBufferWriteReady(SDHCRegisters_t *sdhc)
|
||||
{
|
||||
sdhc->normalInterruptStatus = kBufferWriteReadyInt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Data Timeout
|
||||
|
||||
|
||||
enum SDHCTimeoutControlOffset
|
||||
{
|
||||
kSDHCDataTimeoutCounterOffset = 0,
|
||||
};
|
||||
|
||||
enum SDHCTimeoutControl
|
||||
{
|
||||
kSDHCDataTimeoutCounter = (0xF << kSDHCDataTimeoutCounterOffset),
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
sdhc_setDataTimeoutCounter(SDHCRegisters_t *sdhc)
|
||||
{
|
||||
UInt16 divisor = sdhc->clockControl & kSDClkFrequencySelect;
|
||||
|
||||
// BCOM algorithm
|
||||
UInt8 timeout = 7;
|
||||
while(timeout && (divisor & 1) == 0) {
|
||||
timeout--;
|
||||
divisor >>= 1;
|
||||
}
|
||||
|
||||
bool on = sdhc->errorInterruptStatusEnable & kDataTimeoutErrorInt;
|
||||
sdhc->errorInterruptStatusEnable &= ~kDataTimeoutErrorInt;
|
||||
|
||||
sdhc->timeoutControl |= (divisor & kSDHCDataTimeoutCounter);
|
||||
|
||||
if(on) {
|
||||
sdhc->errorInterruptStatusEnable |= kDataTimeoutErrorInt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Reset
|
||||
|
||||
|
||||
void
|
||||
sdhc_reset(SDHCRegisters_t *sdhc, SDHCResetFlags_t flags)
|
||||
{
|
||||
sdhc->softwareReset |= (flags & (kSDHCResetDataLine | kSDHCResetCmdLine | kSDHCResetAll));
|
||||
}
|
||||
|
||||
SDHCResetFlags_t
|
||||
sdhc_isResetting(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->softwareReset & (kSDHCResetDataLine | kSDHCResetCmdLine | kSDHCResetAll);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Interrupts
|
||||
|
||||
|
||||
bool
|
||||
sdhc_isSignalingInterrupt(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return (sdhc->normalInterruptStatus & sdhc->normalInterruptSignalEnable)
|
||||
|| (sdhc->errorInterruptStatus & sdhc->errorInterruptSignalEnable);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sdhc_clearInterruptSignals(SDHCRegisters_t *sdhc)
|
||||
{
|
||||
UInt16 clear;
|
||||
|
||||
sdhc->forceEventAutoCmd12ErrorStatus = 0;
|
||||
sdhc->forceEventErrorInterruptStatus = 0;
|
||||
|
||||
clear = sdhc->errorInterruptSignalEnable & sdhc->errorInterruptStatus;
|
||||
|
||||
if(clear & kAutoCmd12ErrorInt) {
|
||||
UInt16 cmd12Clear = sdhc->autoCmd12ErrorStatus;
|
||||
sdhc->autoCmd12ErrorStatus = cmd12Clear;
|
||||
}
|
||||
|
||||
sdhc->errorInterruptStatus = clear;
|
||||
|
||||
clear = sdhc->normalInterruptSignalEnable & sdhc->normalInterruptStatus;
|
||||
sdhc->normalInterruptStatus = clear;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Card Interrupt
|
||||
|
||||
|
||||
bool
|
||||
sdhc_isCardInterrupt(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->normalInterruptStatus & kCardInt;
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_enableCardInterrupt(SDHCRegisters_t *sdhc, bool enable)
|
||||
{
|
||||
if(enable) {
|
||||
sdhc->normalInterruptStatusEnable |= kCardInt;
|
||||
sdhc->normalInterruptSignalEnable |= kCardInt;
|
||||
} else {
|
||||
sdhc->normalInterruptStatusEnable &= ~kCardInt;
|
||||
sdhc->normalInterruptSignalEnable &= ~kCardInt;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
sdhc_isCardInterruptEnabled(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
return sdhc->normalInterruptStatusEnable & kCardInt
|
||||
&& sdhc->normalInterruptSignalEnable & kCardInt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Host Control
|
||||
|
||||
|
||||
enum HostControlFieldOffsets
|
||||
{
|
||||
kDataTransferWidthOffset = 1,
|
||||
kHighSpeedEnableOffset = 2,
|
||||
};
|
||||
|
||||
enum HostControlFields
|
||||
{
|
||||
kDataTransferWidth = (1 << kDataTransferWidthOffset), // 1 == 4 bit, 0 == 1 bit
|
||||
kHighSpeedEnable = (1 << kHighSpeedEnableOffset),
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
sdhc_setHighSpeedMode(SDHCRegisters_t *sdhc, bool enabled)
|
||||
{
|
||||
if(enabled) {
|
||||
sdhc->hostControl |= kHighSpeedEnable;
|
||||
} else {
|
||||
sdhc->hostControl &= ~kHighSpeedEnable;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sdhc_setDataTransferWidth(SDHCRegisters_t *sdhc, UInt8 width)
|
||||
{
|
||||
bool cardIntOn = sdhc_isCardInterruptEnabled(sdhc);
|
||||
|
||||
sdhc_enableCardInterrupt(sdhc, false);
|
||||
|
||||
if(width == 4) {
|
||||
sdhc->hostControl |= kDataTransferWidth;
|
||||
} else {
|
||||
sdhc->hostControl &= ~kDataTransferWidth;
|
||||
}
|
||||
|
||||
sdhc_enableCardInterrupt(sdhc, cardIntOn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDIO_SDHC_H
|
||||
#define _SDIO_SDHC_H
|
||||
|
||||
|
||||
#ifdef PLATFORM_VARIANT_IOP
|
||||
#include <sdiocommon/sdio_types.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <IOKit/sdio/sdio_types.h>
|
||||
#include <IOKit/IOTypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark SDHC Register File
|
||||
|
||||
/** Safe typedef for use of SDHCRegisters register file. */
|
||||
typedef volatile struct SDHCRegisters SDHCRegisters_t;
|
||||
|
||||
/** Standard SDIO Host Controller 2.0 Register File. */
|
||||
struct SDHCRegisters
|
||||
{
|
||||
// SD Command Generation: 0x00 - 0x0F
|
||||
volatile UInt32 sdmaSystemAddr;
|
||||
volatile UInt16 blockSize;
|
||||
volatile UInt16 blockCount;
|
||||
volatile UInt32 argument;
|
||||
volatile UInt16 transferMode;
|
||||
volatile UInt16 command;
|
||||
|
||||
// Response: 0x10 - 0x1F
|
||||
volatile UInt32 response[4];
|
||||
|
||||
// Buffer Data Port: 0x20 - 0x23
|
||||
volatile UInt32 bufferDataPort;
|
||||
|
||||
// Host Controls: 0x24 - 0x2F
|
||||
volatile UInt32 presentState;
|
||||
volatile UInt8 hostControl;
|
||||
volatile UInt8 powerControl;
|
||||
volatile UInt8 blockGapControl;
|
||||
volatile UInt8 wakeupControl;
|
||||
volatile UInt16 clockControl;
|
||||
volatile UInt8 timeoutControl;
|
||||
volatile UInt8 softwareReset;
|
||||
|
||||
// Interrupt Controls: 0x30 - 0x3D
|
||||
volatile UInt16 normalInterruptStatus;
|
||||
volatile UInt16 errorInterruptStatus;
|
||||
volatile UInt16 normalInterruptStatusEnable;
|
||||
volatile UInt16 errorInterruptStatusEnable;
|
||||
volatile UInt16 normalInterruptSignalEnable;
|
||||
volatile UInt16 errorInterruptSignalEnable;
|
||||
volatile UInt16 autoCmd12ErrorStatus;
|
||||
volatile UInt8 __reservedIntArea[2] SDIO_RESERVED; // Do not use, will change
|
||||
|
||||
// Capabilities: 0x40 - 0x4F
|
||||
volatile UInt64 capabilities;
|
||||
volatile UInt64 maxCurrentCapabilities;
|
||||
|
||||
// Force Event: 0x50 - 0x53
|
||||
volatile UInt16 forceEventAutoCmd12ErrorStatus;
|
||||
volatile UInt16 forceEventErrorInterruptStatus;
|
||||
|
||||
// ADMA: 0x54 - 0x5F
|
||||
volatile UInt8 admaErrorStatus;
|
||||
volatile UInt8 __reservedCapArea[3] SDIO_RESERVED; // Do not use, will change
|
||||
volatile UInt64 admaSystemAddr;
|
||||
|
||||
// Reserved: 0x60 - 0xEF
|
||||
volatile UInt8 __reserved[0x90] SDIO_RESERVED; // Do not use, will change
|
||||
|
||||
// Common Area: 0xF0 - 0xFF
|
||||
volatile UInt8 __reservedCommonArea[0xC] SDIO_RESERVED; // Do not use, will change
|
||||
volatile UInt16 slotInterruptStatus;
|
||||
volatile UInt16 hostControllerVersion;
|
||||
};
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark SDHC Register Bits
|
||||
|
||||
enum SDIOTransferModeField
|
||||
{
|
||||
kSDIOTransferEnableDMA = (1 << 0),
|
||||
kSDIOTransferEnableBlockCount = (1 << 1),
|
||||
kSDIOTransferEnableAutoCmd12 = (1 << 2),
|
||||
|
||||
kSDIOTransferReadFromCard = (1 << 4),
|
||||
kSDIOTransferMultipleBlocks = (1 << 5),
|
||||
};
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Capabilities
|
||||
|
||||
UInt16 sdhc_getMaxBlockLength(const SDHCRegisters_t *sdhc);
|
||||
|
||||
UInt32 sdhc_getBaseClockFrequencyHz(const SDHCRegisters_t *sdhc);
|
||||
|
||||
bool sdhc_isSuspendResumeSupported(const SDHCRegisters_t *sdhc);
|
||||
|
||||
bool sdhc_isHighSpeedSupported(const SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Present State
|
||||
|
||||
bool sdhc_isCommandInhibitedOnCmd(const SDHCRegisters_t *sdhc);
|
||||
|
||||
bool sdhc_isCommandInhibitedOnData(const SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Clocks
|
||||
|
||||
/** @brief Sets the SD Clock rate.
|
||||
* @param[in] hcReg
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in] targetSDClkRateHz
|
||||
* Desired SD Clock rate, in Hz
|
||||
* @param[in] inputClkRateHz
|
||||
* SD Block's input clock rate, in Hz
|
||||
* @return
|
||||
* The actual clock rate set, in Hz.
|
||||
*/
|
||||
UInt32 sdhc_setClockDividerRate(SDHCRegisters_t *sdhc, UInt32 targetSDClkRateHz, UInt32 inputClkRateHz);
|
||||
|
||||
void sdhc_setClockDivider(SDHCRegisters_t *sdhc, UInt16 divider);
|
||||
|
||||
UInt16 sdhc_getClockDivider(const SDHCRegisters_t *sdhc);
|
||||
|
||||
void sdhc_enableInternalClock(SDHCRegisters_t *sdhc, bool enable);
|
||||
|
||||
bool sdhc_isInternalClockStable(const SDHCRegisters_t *sdhc);
|
||||
|
||||
void sdhc_enableSDClock(SDHCRegisters_t *sdhc, bool enable);
|
||||
|
||||
bool sdhc_isSDClockEnabled(const SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Block Size
|
||||
|
||||
void sdhc_setBlockSize(SDHCRegisters_t *sdhc, UInt16 size);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Commands
|
||||
|
||||
void sdhc_copyCommandResponse(const SDHCRegisters_t *sdhc, struct SDIOCommandResponse *response);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Command State
|
||||
|
||||
/** @brief Enable/Disable status bits needed for command completion and error checking. */
|
||||
void sdhc_enableCommandStatus(SDHCRegisters_t *sdhc, bool enable);
|
||||
|
||||
/** @brief True if the command has completed for any reason. */
|
||||
bool sdhc_isCommandComplete(const SDHCRegisters_t *sdhc);
|
||||
|
||||
/** @brief Gets the command status after completion. */
|
||||
SDIOReturn_t sdhc_getCommandStatus(const SDHCRegisters_t *sdhc);
|
||||
|
||||
/** @brief Clear status bits needed for command completion and error checking. */
|
||||
void sdhc_clearCommandStatus(SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Transfer State
|
||||
|
||||
/** @brief Enable/Disable status bits needed for transfer completion and error checking. */
|
||||
void sdhc_enableTransferStatus(SDHCRegisters_t *sdhc, bool enable);
|
||||
|
||||
/** @brief True if the transfer has completed for any reason. */
|
||||
bool sdhc_isTransferComplete(const SDHCRegisters_t *sdhc);
|
||||
|
||||
/** @brief Gets the current transfer status after completion. */
|
||||
SDIOReturn_t sdhc_getTransferStatus(const SDHCRegisters_t *sdhc);
|
||||
|
||||
/** @brief Clear status bits needed for transfer completion and error checking. */
|
||||
void sdhc_clearTransferStatus(SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PIO
|
||||
|
||||
bool sdhc_isBufferReadReady(const SDHCRegisters_t *sdhc);
|
||||
|
||||
void sdhc_enableBufferReadReady(SDHCRegisters_t *sdhc, bool enable);
|
||||
|
||||
void sdhc_clearBufferReadReady(SDHCRegisters_t *sdhc);
|
||||
|
||||
bool sdhc_isBufferWriteReady(const SDHCRegisters_t *sdhc);
|
||||
|
||||
void sdhc_enableBufferWriteReady(SDHCRegisters_t *sdhc, bool enable);
|
||||
|
||||
void sdhc_clearBufferWriteReady(SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Data Timeout
|
||||
|
||||
void sdhc_setDataTimeoutCounter(SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Reset
|
||||
|
||||
enum SDHCResetFlags
|
||||
{
|
||||
kSDHCResetAll = (1 << 0),
|
||||
kSDHCResetCmdLine = (1 << 1),
|
||||
kSDHCResetDataLine = (1 << 2),
|
||||
};
|
||||
typedef UInt8 SDHCResetFlags_t;
|
||||
|
||||
void sdhc_reset(SDHCRegisters_t *sdhc, SDHCResetFlags_t flags);
|
||||
|
||||
SDHCResetFlags_t sdhc_isResetting(const SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Interrupts
|
||||
|
||||
bool sdhc_isSignalingInterrupt(const SDHCRegisters_t *sdhc);
|
||||
|
||||
/** @brief Clear all interrupt signals.
|
||||
* Only the status fields that are signaling an interrupt are cleared.
|
||||
*/
|
||||
void sdhc_clearInterruptSignals(SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Card Interrupt
|
||||
|
||||
bool sdhc_isCardInterrupt(const SDHCRegisters_t *sdhc);
|
||||
|
||||
void sdhc_enableCardInterrupt(SDHCRegisters_t *sdhc, bool enable);
|
||||
|
||||
bool sdhc_isCardInterruptEnabled(const SDHCRegisters_t *sdhc);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Host Control
|
||||
|
||||
void sdhc_setHighSpeedMode(SDHCRegisters_t *sdhc, bool enabled);
|
||||
|
||||
void sdhc_setDataTransferWidth(SDHCRegisters_t *sdhc, UInt8 width);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SDIO_SDHC_H */
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDIO_CCCR_H_
|
||||
#define _SDIO_CCCR_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
enum SDIOCccrRegisterAddress
|
||||
{
|
||||
kSDIOCccrRevisionAddr = 0x00,
|
||||
kSDIOCccrSpecRevAddr = 0x01,
|
||||
kSDIOCccrIOEnableAddr = 0x02,
|
||||
kSDIOCccrIOReadyAddr = 0x03,
|
||||
kSDIOCccrIntEnableAddr = 0x04,
|
||||
kSDIOCccrIntPendingAddr = 0x05,
|
||||
kSDIOCccrIOAbortAddr = 0x06,
|
||||
kSDIOCccrBusInterfaceControlAddr= 0x07,
|
||||
kSDIOCccrCardCapabilityAddr = 0x08,
|
||||
kSDIOCccrCommonCISPtrLowAddr = 0x09,
|
||||
kSDIOCccrCommonCISPtrMidAddr = 0x0A,
|
||||
kSDIOCccrCommonCISPtrHighAddr = 0x0B,
|
||||
kSDIOCccrBusSuspendAddr = 0x0C,
|
||||
kSDIOCccrFunctionSelectAddr = 0x0D,
|
||||
kSDIOCccrExecFlagsAddr = 0x0E,
|
||||
kSDIOCccrReadyFlagsAddr = 0x0F,
|
||||
kSDIOCccrFn0BlockSizeLSBAddr = 0x10,
|
||||
kSDIOCccrFn0BlockSizeMSBAddr = 0x11,
|
||||
kSDIOCccrPowerControlAddr = 0x12,
|
||||
kSDIOCccrHighSpeedAddr = 0x13,
|
||||
};
|
||||
|
||||
|
||||
// Bus Interface Control
|
||||
enum SDIOCccrBusInterfaceControlMask
|
||||
{
|
||||
kSDIOCccrBusWidthMask = (1 << 1) | (1 << 0),
|
||||
};
|
||||
|
||||
enum SDIOCccrBusInterfaceControl
|
||||
{
|
||||
kSDIOCccrBusIfWidth1Bit = ((0 << 1)|(0 << 0)),
|
||||
kSDIOCccrBusIfWidth4Bit = ((1 << 1)|(0 << 0)),
|
||||
|
||||
kSDIOCccrBusIfContinuousSPIIntEnabled = (1 << 5),
|
||||
kSDIOCccrBusIfContinuousSPIInt = (1 << 6),
|
||||
kSDIOCccrBusIfCardDetectDisable = (1 << 7),
|
||||
};
|
||||
|
||||
|
||||
// Card Capabilities
|
||||
|
||||
enum SDIOCccrCardCapability
|
||||
{
|
||||
kSDIOCccrCapDirectCommands = (1 << 0),
|
||||
kSDIOCccrCapMultiBlock = (1 << 1),
|
||||
kSDIOCccrCapReadWait = (1 << 2),
|
||||
kSDIOCccrCapSuspendResume = (1 << 3),
|
||||
kSDIOCccrCap4BitIntraBlockInt = (1 << 4),
|
||||
kSDIOCccrCap4BitIntraBlockIntEnable = (1 << 5),
|
||||
kSDIOCccrCapLowSpeed = (1 << 6),
|
||||
kSDIOCccrCap4BitLowSpeed = (1 << 7),
|
||||
};
|
||||
|
||||
|
||||
// High Speed
|
||||
|
||||
enum SDIOCccrHighSpeed
|
||||
{
|
||||
kSDIOCccrHighSpeedSupported = (1 << 0),
|
||||
kSDIOCccrHighSpeedEnabled = (1 << 1),
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SDIO_CCCR_H_ */
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDIO_CIS_H
|
||||
#define _SDIO_CIS_H
|
||||
|
||||
|
||||
#ifdef PLATFORM_VARIANT_IOP
|
||||
#include <sdiocommon/sdio_types.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <IOKit/sdio/sdio_types.h>
|
||||
#include <IOKit/IOTypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum SDIOCISTupleCode {
|
||||
kSDIOCISTupleNull = 0x00,
|
||||
kSDIOCISTupleChecksum = 0x10,
|
||||
kSDIOCISTupleVers1 = 0x15,
|
||||
kSDIOCISTupleManfID = 0x20,
|
||||
kSDIOCISTupleFuncID = 0x21,
|
||||
kSDIOCISTupleFuncE = 0x22,
|
||||
|
||||
kSDIOCISTupleSDIOStd = 0x91,
|
||||
kSDIOCISTupleSDIOExt = 0x92,
|
||||
kSDIOCISTupleEnd = 0xFF,
|
||||
|
||||
kSDIOCISTupleVendor80 = 0x80,
|
||||
kSDIOCISTupleVendor81 = 0x81,
|
||||
kSDIOCISTupleVendor82 = 0x82,
|
||||
kSDIOCISTupleVendor83 = 0x83,
|
||||
kSDIOCISTupleVendor84 = 0x84,
|
||||
kSDIOCISTupleVendor85 = 0x85,
|
||||
kSDIOCISTupleVendor86 = 0x86,
|
||||
kSDIOCISTupleVendor87 = 0x87,
|
||||
kSDIOCISTupleVendor88 = 0x88,
|
||||
kSDIOCISTupleVendor89 = 0x89,
|
||||
kSDIOCISTupleVendor8A = 0x8A,
|
||||
kSDIOCISTupleVendor8B = 0x8B,
|
||||
kSDIOCISTupleVendor8C = 0x8C,
|
||||
kSDIOCISTupleVendor8D = 0x8D,
|
||||
kSDIOCISTupleVendor8E = 0x8E,
|
||||
kSDIOCISTupleVendor8F = 0x8F,
|
||||
};
|
||||
|
||||
enum SDIOCISTupleHeaderSize
|
||||
{
|
||||
kSDIOCISTupleSpecialHeaderSize = 1 * sizeof(UInt8),
|
||||
kSDIOCISTupleStandardHeaderSize = 2 * sizeof(UInt8),
|
||||
};
|
||||
|
||||
|
||||
struct SDIOCISTupleChecksum
|
||||
{
|
||||
UInt16 address;
|
||||
UInt16 length;
|
||||
UInt8 checksum;
|
||||
} SDIO_PACKED;
|
||||
|
||||
|
||||
struct SDIOCISTupleVers1
|
||||
{
|
||||
UInt8 major;
|
||||
UInt8 minor;
|
||||
UInt8 strings[0];
|
||||
} SDIO_PACKED;
|
||||
|
||||
enum
|
||||
{
|
||||
kSDIOCISTupleVers1NumStrings = 4,
|
||||
|
||||
/** Minimum size of the Vers1 body.
|
||||
* This is: major + minor + NULL for each string + end of chain
|
||||
*/
|
||||
kSDIOCISTupleVers1MinBodySize = 2 + kSDIOCISTupleVers1NumStrings + 1,
|
||||
};
|
||||
|
||||
|
||||
struct SDIOCISTupleManfID
|
||||
{
|
||||
UInt16 manufacturerID;
|
||||
UInt16 cardID;
|
||||
} SDIO_PACKED;
|
||||
|
||||
struct SDIOCISTupleFuncID
|
||||
{
|
||||
UInt8 functionCode;
|
||||
UInt8 sysVInitMask;
|
||||
} SDIO_PACKED;
|
||||
|
||||
struct SDIOCISTupleFunc0E
|
||||
{
|
||||
UInt8 type;
|
||||
UInt16 fn0BlockSize;
|
||||
UInt8 maxTransferSpeed;
|
||||
} SDIO_PACKED;
|
||||
|
||||
struct SDIOCISTupleFuncE
|
||||
{
|
||||
UInt8 type;
|
||||
UInt8 functionInfo;
|
||||
UInt8 stdIORev;
|
||||
UInt32 cardPSN;
|
||||
UInt32 csaSize;
|
||||
UInt8 csaProperty;
|
||||
UInt16 maxBlockSize;
|
||||
UInt32 ocr;
|
||||
UInt8 operatingMinPower;
|
||||
UInt8 operatingpAvgPower;
|
||||
UInt8 operatingMaxPower;
|
||||
UInt8 standbyMinPower;
|
||||
UInt8 standbyAvgPower;
|
||||
UInt8 standbyMaxPower;
|
||||
UInt16 minBandwidth;
|
||||
UInt16 optimalBandwidth;
|
||||
UInt16 enableTimeoutValue;
|
||||
UInt16 spAvgPower33;
|
||||
UInt16 spMaxPower33;
|
||||
UInt16 highCurrentAvgPower33;
|
||||
UInt16 highCurrentMaxPower33;
|
||||
UInt16 lowCurrentAvgPower33;
|
||||
UInt16 lowCurrentMaxPower33;
|
||||
} SDIO_PACKED;
|
||||
|
||||
struct SDIOCISTupleStd
|
||||
{
|
||||
UInt8 stdID;
|
||||
UInt8 stdType;
|
||||
UInt8 stdData[0];
|
||||
} SDIO_PACKED;
|
||||
|
||||
struct SDIOCISTupleExt
|
||||
{
|
||||
UInt8 extData[0];
|
||||
} SDIO_PACKED;
|
||||
|
||||
|
||||
struct SDIOCisTupleHeader
|
||||
{
|
||||
UInt8 code;
|
||||
UInt8 link;
|
||||
} SDIO_PACKED;
|
||||
|
||||
union SDIOCisTupleBody
|
||||
{
|
||||
struct SDIOCISTupleChecksum checksumTpl;
|
||||
struct SDIOCISTupleVers1 vers1Tpl;
|
||||
struct SDIOCISTupleManfID manfIDTpl;
|
||||
struct SDIOCISTupleFuncID funcIDTpl;
|
||||
struct SDIOCISTupleFunc0E func0ETpl;
|
||||
struct SDIOCISTupleFuncE funcETpl;
|
||||
struct SDIOCISTupleStd stdTpl;
|
||||
struct SDIOCISTupleExt extTpl;
|
||||
UInt8 byte[0];
|
||||
} SDIO_PACKED;
|
||||
|
||||
struct SDIOCISTuple
|
||||
{
|
||||
struct SDIOCisTupleHeader header;
|
||||
union SDIOCisTupleBody body;
|
||||
} SDIO_PACKED;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _SDIO_CIS_H */
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include "sdio_cmdfields.h"
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Common
|
||||
|
||||
enum CommandOffset
|
||||
{
|
||||
kSDIOCmdAddressOffset = 9,
|
||||
kSDIOCmdFunctionOffset = 28,
|
||||
};
|
||||
|
||||
enum CommandMask
|
||||
{
|
||||
kSDIOCmdFunctionMask = 0x7,
|
||||
kSDIOCmdAddressMask = 0x1FFFF,
|
||||
};
|
||||
|
||||
enum SDIOCmdDirection
|
||||
{
|
||||
kSDIOCmdDirectionRead = (0 << 31),
|
||||
kSDIOCmdDirectionWrite = (1 << 31),
|
||||
};
|
||||
|
||||
|
||||
static inline UInt32
|
||||
convertFunctionToArg(UInt8 function)
|
||||
{
|
||||
return (function & kSDIOCmdFunctionMask) << kSDIOCmdFunctionOffset;
|
||||
}
|
||||
|
||||
static inline UInt32
|
||||
convertAddressToArg(UInt32 address)
|
||||
{
|
||||
return (address & kSDIOCmdAddressMask) << kSDIOCmdAddressOffset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum SDIODirection
|
||||
sdio_getCommandDirection(enum SDIOCommandIndex index, UInt32 argument)
|
||||
{
|
||||
switch (index) {
|
||||
case kSDIOCmd52_IORWDirect:
|
||||
case kSDIOCmd53_IORWExtended:
|
||||
return (argument & kSDIOCmdDirectionWrite) ? kSDIODirectionWrite : kSDIODirectionRead;
|
||||
default:
|
||||
return kSDIODirectionNone;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Cmd5
|
||||
|
||||
UInt32
|
||||
sdio_getOCR(const struct SDIOCommandResponse *cmd5Response)
|
||||
{
|
||||
return cmd5Response->response[0] & 0x00fffff;
|
||||
}
|
||||
|
||||
bool
|
||||
sdio_getNumIOFunctions(const struct SDIOCommandResponse *cmd5Response)
|
||||
{
|
||||
return (cmd5Response->response[0] & 0x70000000) >> 28;
|
||||
}
|
||||
|
||||
bool
|
||||
sdio_isMemoryPresent(const struct SDIOCommandResponse *cmd5Response)
|
||||
{
|
||||
return cmd5Response->response[0] & 0x08000000; // >> 27
|
||||
}
|
||||
|
||||
bool
|
||||
sdio_isIOReady(const struct SDIOCommandResponse *cmd5Response)
|
||||
{
|
||||
return cmd5Response->response[0] & 0x80000000; // >> 31
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Cmd52
|
||||
|
||||
|
||||
UInt32
|
||||
sdio_generateCmd52Arg(enum SDIODirection direction,
|
||||
UInt8 sdioFunction, UInt32 cardAddress, UInt8 data,
|
||||
SDIOCmd52Flags flags)
|
||||
{
|
||||
UInt32 dir = (direction & kSDIODirectionWrite) ? kSDIOCmdDirectionWrite : kSDIOCmdDirectionRead;
|
||||
|
||||
return dir | convertFunctionToArg(sdioFunction) | flags
|
||||
| convertAddressToArg(cardAddress) | data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Cmd53
|
||||
|
||||
enum SDIOCmd53Mask
|
||||
{
|
||||
kSDIOCmd53CountMask = 0x1FF
|
||||
};
|
||||
|
||||
|
||||
static inline UInt32
|
||||
convertCmd53CountToArg(UInt32 count)
|
||||
{
|
||||
return (count & kSDIOCmd53CountMask);
|
||||
}
|
||||
|
||||
|
||||
UInt32
|
||||
sdio_generateCmd53Arg(enum SDIODirection direction,
|
||||
UInt8 sdioFunction, UInt32 cardAddress, UInt16 count,
|
||||
SDIOCmd53Flags flags)
|
||||
{
|
||||
UInt32 dir = (direction & kSDIODirectionWrite) ? kSDIOCmdDirectionWrite : kSDIOCmdDirectionRead;
|
||||
|
||||
return dir | convertFunctionToArg(sdioFunction) | flags
|
||||
| convertAddressToArg(cardAddress) | convertCmd53CountToArg(count);
|
||||
}
|
||||
|
||||
UInt16
|
||||
sdio_getCmd53Count(UInt32 cmdArg)
|
||||
{
|
||||
return cmdArg & kSDIOCmd53CountMask;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDIO_CMDFIELDS_H_
|
||||
#define _SDIO_CMDFIELDS_H_
|
||||
|
||||
|
||||
#ifdef PLATFORM_VARIANT_IOP
|
||||
#include <sdiocommon/sdio_types.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <IOKit/sdio/sdio_types.h>
|
||||
#include <IOKit/IOTypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Common
|
||||
|
||||
enum SDIODirection sdio_getCommandDirection(enum SDIOCommandIndex index, UInt32 argument);
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Cmd 5
|
||||
|
||||
enum SDIOCmd5OperationConditions {
|
||||
kSDIOOpCond_None = (0x000000),
|
||||
|
||||
kSDIOOpCond_20_21 = (1 << 8),
|
||||
kSDIOOpCond_21_22 = (1 << 9),
|
||||
kSDIOOpCond_22_23 = (1 << 10),
|
||||
kSDIOOpCond_23_24 = (1 << 11),
|
||||
kSDIOOpCond_24_25 = (1 << 12),
|
||||
kSDIOOpCond_25_26 = (1 << 13),
|
||||
kSDIOOpCond_26_27 = (1 << 14),
|
||||
kSDIOOpCond_27_28 = (1 << 15),
|
||||
kSDIOOpCond_28_29 = (1 << 16),
|
||||
kSDIOOpCond_29_30 = (1 << 17),
|
||||
kSDIOOpCond_30_31 = (1 << 18),
|
||||
kSDIOOpCond_31_32 = (1 << 19),
|
||||
kSDIOOpCond_32_33 = (1 << 20),
|
||||
kSDIOOpCond_33_34 = (1 << 21),
|
||||
kSDIOOpCond_34_35 = (1 << 22),
|
||||
kSDIOOpCond_35_36 = (1 << 23),
|
||||
|
||||
kSDIOOpCond_All = (0xFFFF00)
|
||||
};
|
||||
|
||||
UInt32 sdio_getOCR(const struct SDIOCommandResponse *cmd5Response);
|
||||
|
||||
bool sdio_getNumIOFunctions(const struct SDIOCommandResponse *cmd5Response);
|
||||
|
||||
bool sdio_isMemoryPresent(const struct SDIOCommandResponse *cmd5Response);
|
||||
|
||||
bool sdio_isIOReady(const struct SDIOCommandResponse *cmd5Response);
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Cmd 52
|
||||
|
||||
|
||||
enum SDIOCmd52Flag
|
||||
{
|
||||
kSDIOCmd52RAW = (1 << 27),
|
||||
};
|
||||
|
||||
typedef UInt32 SDIOCmd52Flags;
|
||||
|
||||
|
||||
UInt32 sdio_generateCmd52Arg(enum SDIODirection direction,
|
||||
UInt8 sdioFunction, UInt32 cardAddress, UInt8 data,
|
||||
SDIOCmd52Flags flags);
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Cmd 53
|
||||
|
||||
|
||||
enum SDIOCmd53Flag
|
||||
{
|
||||
kSDIOCmd53ByteMode = (0 << 27),
|
||||
kSDIOCmd53BlockMode = (1 << 27),
|
||||
kSDIOCmd53FixedAddress = (0 << 26),
|
||||
kSDIOCmd53IncrementAddress = (1 << 26),
|
||||
};
|
||||
|
||||
typedef UInt32 SDIOCmd53Flags;
|
||||
|
||||
|
||||
UInt32 sdio_generateCmd53Arg(enum SDIODirection direction,
|
||||
UInt8 sdioFunction, UInt32 cardAddress, UInt16 count,
|
||||
SDIOCmd53Flags flags);
|
||||
|
||||
UInt16 sdio_getCmd53Count(UInt32 cmdArg);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SDIO_CMDFIELDS_H_ */
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include "sdio_cmdprop.h"
|
||||
|
||||
#include "sdio_types.h"
|
||||
|
||||
|
||||
enum CommandRegFieldOffsets
|
||||
{
|
||||
kResponseTypeOffset = 0,
|
||||
kCmdCRCCheckEnabledOffset = 3,
|
||||
kCmdIndexCheckEnabledOffset = 4,
|
||||
kDataPresentSelectOffset = 5,
|
||||
kCommandTypeOffset = 6,
|
||||
kCommandIndexOffset = 8,
|
||||
};
|
||||
|
||||
enum CommandRegFieldMasks
|
||||
{
|
||||
kResponseTypeSelectMask = (0x3 << kResponseTypeOffset),
|
||||
kCmdCRCCheckEnabled = (1 << kCmdCRCCheckEnabledOffset),
|
||||
kCmdIndexCheckEnabled = (1 << kCmdIndexCheckEnabledOffset),
|
||||
kDataPresentSelect = (1 << kDataPresentSelectOffset),
|
||||
kCommandTypeMask = (0x3 << kCommandTypeOffset),
|
||||
kCommandIndexMask = (0x3F << kCommandIndexOffset),
|
||||
};
|
||||
|
||||
enum CommandRegCommandType
|
||||
{
|
||||
kSDIOCommandNormal = (0x0 << kCommandTypeOffset),
|
||||
kSDIOCommandSuspend = (0x1 << kCommandTypeOffset),
|
||||
kSDIOCommandResume = (0x2 << kCommandTypeOffset),
|
||||
kSDIOCommandAbort = (0x3 << kCommandTypeOffset),
|
||||
};
|
||||
|
||||
enum CommandRegResponseTypeSelect
|
||||
{
|
||||
kNoResponse = (0x0 << kResponseTypeOffset),
|
||||
kResponseLength136 = (0x1 << kResponseTypeOffset),
|
||||
kResponseLength48 = (0x2 << kResponseTypeOffset),
|
||||
kResponseLength48CheckBusy = (0x3 << kResponseTypeOffset),
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
sdio_isDataPresent(UInt16 cmdIndex)
|
||||
{
|
||||
// TODO: Support other data commands
|
||||
return kSDIOCmd53_IORWExtended == cmdIndex;
|
||||
}
|
||||
|
||||
static bool
|
||||
sdio_shouldCheckIndex(UInt16 cmdIndex)
|
||||
{
|
||||
return cmdIndex != kSDIOCmd5_IOSendOpCond;
|
||||
}
|
||||
|
||||
static bool
|
||||
sdio_shouldCheckCRC(UInt16 cmdIndex)
|
||||
{
|
||||
return cmdIndex != kSDIOCmd5_IOSendOpCond;
|
||||
}
|
||||
|
||||
static enum CommandRegResponseTypeSelect
|
||||
sdio_getResponseType(UInt16 cmdIndex)
|
||||
{
|
||||
// TODO: Support other response types
|
||||
return kResponseLength48;
|
||||
}
|
||||
|
||||
UInt16 sdio_generateCommand(UInt16 cmdIndex)
|
||||
{
|
||||
UInt16 cmd = 0;
|
||||
|
||||
// Command Index
|
||||
cmd |= (cmdIndex << kCommandIndexOffset) & kCommandIndexMask;
|
||||
|
||||
// Command Type
|
||||
// TODO: Support abort & suspend / resume commands
|
||||
cmd |= kSDIOCommandNormal;
|
||||
|
||||
// Data present select
|
||||
if(sdio_isDataPresent(cmdIndex)) {
|
||||
cmd |= kDataPresentSelect;
|
||||
}
|
||||
|
||||
// Command Index Check
|
||||
if(sdio_shouldCheckIndex(cmdIndex)) {
|
||||
cmd |= kCmdIndexCheckEnabled;
|
||||
}
|
||||
|
||||
// Command CRC Check
|
||||
if(sdio_shouldCheckCRC(cmdIndex)) {
|
||||
cmd |= kCmdCRCCheckEnabled;
|
||||
}
|
||||
|
||||
// Response type select
|
||||
cmd |= sdio_getResponseType(cmdIndex);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDIO_CMDPROP_H
|
||||
#define _SDIO_CMDPROP_H
|
||||
|
||||
|
||||
#ifdef PLATFORM_VARIANT_IOP
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <IOKit/IOTypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** @brief true if the command has an associated data transfer. */
|
||||
bool sdio_isDataPresent(UInt16 cmdIndex);
|
||||
|
||||
/** @brief Generates the value for the command register. */
|
||||
UInt16 sdio_generateCommand(UInt16 cmdIndex);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SDIO_CMDPROP_H */
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SDIO_TYPES_H_
|
||||
#define _SDIO_TYPES_H_
|
||||
|
||||
|
||||
#ifdef PLATFORM_VARIANT_IOP
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <IOKit/IOTypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SDIO_PACKED __attribute__((packed))
|
||||
#define SDIO_DEPRECATED __attribute__((deprecated))
|
||||
#define SDIO_RESERVED __attribute__((deprecated))
|
||||
#else
|
||||
#error Unknown Compiler
|
||||
#endif
|
||||
|
||||
|
||||
typedef UInt32 IOSDIOClockRate;
|
||||
|
||||
enum
|
||||
{
|
||||
kIOSDIOMaxClockRate = 50000000
|
||||
};
|
||||
|
||||
enum IOSDIOClockMode
|
||||
{
|
||||
kIOSDIOClockOff = -1,
|
||||
kIOSDIOClockOn = +1
|
||||
};
|
||||
|
||||
enum IOSDIOBusWidth
|
||||
{
|
||||
kIOSDIO1BitMode = 1,
|
||||
kIOSDIO4BitMode = 4
|
||||
};
|
||||
|
||||
enum IOSDIOBusSpeedMode
|
||||
{
|
||||
kIOSDIONormalSpeed = 1,
|
||||
kIOSDIOHighSpeed = 2
|
||||
};
|
||||
|
||||
|
||||
enum SDIOCommandIndex
|
||||
{
|
||||
kSDIOCmd0_GoIdleState = 0,
|
||||
kSDIOCmd1_SendOpCond = 1,
|
||||
kSDIOCmd2_AllSendCID = 2,
|
||||
kSDIOCmd3_SendRelativeAddr = 3,
|
||||
kSDIOCmd4_SetDSR = 4,
|
||||
kSDIOCmd5_IOSendOpCond = 5,
|
||||
kSDIOCmd6_SwitchFunc = 6,
|
||||
kSDIOCmd7_SelectDeselectCard = 7,
|
||||
kSDIOCmd9_SendCSD = 9,
|
||||
kSDIOCmd10_SendCID = 10,
|
||||
kSDIOCmd12_StopTransmission = 12,
|
||||
kSDIOCmd13_SendStatus = 13,
|
||||
kSDIOCmd15_GoInactiveState = 15,
|
||||
kSDIOCmd16_SetBlockLength = 16,
|
||||
kSDIOCmd17_ReadSingleBlock = 17,
|
||||
kSDIOCmd18_ReadMultipleBlock = 18,
|
||||
kSDIOCmd24_WriteBlock = 24,
|
||||
kSDIOCmd25_WriteMultipleBlock = 25,
|
||||
kSDIOCmd27_ProgramCSD = 27,
|
||||
kSDIOCmd28_SetWriteProt = 28,
|
||||
kSDIOCmd29_ClearWriteProt = 29,
|
||||
kSDIOCmd30_SendWriteProt = 30,
|
||||
kSDIOCmd32_EraseWrBlkStart = 32,
|
||||
kSDIOCmd33_EraseWrBlkEnd = 33,
|
||||
kSDIOCmd38_Erase = 38,
|
||||
kSDIOCmd42_LockUnlock = 42,
|
||||
kSDIOCmd52_IORWDirect = 52,
|
||||
kSDIOCmd53_IORWExtended = 53,
|
||||
kSDIOCmd55_AppCmd = 55,
|
||||
kSDIOCmd56_GenCmd = 56,
|
||||
kSDIOCmd58_ReadOCR = 58,
|
||||
kSDIOCmd59_CRCOnOff = 59,
|
||||
|
||||
kSDIOAcmd6_SetBusWidth = 6,
|
||||
kSDIOAcmd13_SDStatus = 13,
|
||||
kSDIOAcmd22_SendNumWrBlocks = 22,
|
||||
kSDIOAcmd23_SetWrBlkEraseCount = 23,
|
||||
kSDIOAcmd41_SDAppOpCond = 41,
|
||||
kSDIOAcmd42_SetClrCardDetect = 42,
|
||||
kSDIOAcmd51_SendSCR = 51,
|
||||
};
|
||||
|
||||
enum SDIODirection
|
||||
{
|
||||
kSDIODirectionNone = 0, // Same as kIODirectionNone
|
||||
kSDIODirectionRead = (1 << 0), // Same as kIODirectionIn
|
||||
kSDIODirectionWrite = (1 << 1), // Same as kIODirectionOut
|
||||
};
|
||||
|
||||
struct SDIOCommand
|
||||
{
|
||||
UInt16 index; // SDIOCommandIndex
|
||||
UInt32 argument;
|
||||
};
|
||||
|
||||
struct SDIOCommandResponse
|
||||
{
|
||||
UInt32 response[4];
|
||||
};
|
||||
|
||||
struct SDIOMemorySegments
|
||||
{
|
||||
UInt64 dataLength;
|
||||
UInt32 segmentCount;
|
||||
void *segmentList;
|
||||
};
|
||||
|
||||
struct SDIOTransfer
|
||||
{
|
||||
struct SDIOCommand command;
|
||||
UInt8 direction; // SDIODirection
|
||||
UInt16 blockSize;
|
||||
UInt16 blockCount;
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum SDIOReturn
|
||||
{
|
||||
/** @brief Success. */
|
||||
kSDIOReturnSuccess = 0,
|
||||
|
||||
// Generic IOReturn-derived Errors
|
||||
|
||||
/** @brief Invalid Argument. */
|
||||
kSDIOReturnBadArgument = 0x2c2,
|
||||
|
||||
/** @brief Can't allocate memory. */
|
||||
kSDIOReturnNoMemory = 0x2bd,
|
||||
|
||||
|
||||
// General SDIO Errors
|
||||
|
||||
/** @brief General SDIO Error. */
|
||||
kSDIOReturnSDIOError = 0x300,
|
||||
|
||||
|
||||
// Host Controller Errors
|
||||
|
||||
/** @brief General Host Controller Error. */
|
||||
kSDIOReturnSDHCError = 0x400,
|
||||
|
||||
/** @brief Host controller physical address invalid. */
|
||||
kSDIOReturnNoHostController = 0x401,
|
||||
|
||||
/** @brief Couldn't perform command because SD Clock is disabled. */
|
||||
kSDIOReturnInternalClockUnstable= 0x402,
|
||||
|
||||
/** @brief Couldn't perform command because SD Clock is disabled. */
|
||||
kSDIOReturnSDClockDisabled = 0x403,
|
||||
|
||||
/** @brief Failed due to errors in ADMA transfer. */
|
||||
kSDIOReturnADMAError = 0x404,
|
||||
|
||||
/** @brief Failed due to errors in SDMA transfer. */
|
||||
kSDIOReturnSDMAError = 0x405,
|
||||
|
||||
/** @brief Error performing Auto CMD12. */
|
||||
kSDIOReturnAutoCMD12Error = 0x406,
|
||||
|
||||
/** @brief HC not supplying power to card. */
|
||||
kSDIOReturnCurrentLimitError = 0x407,
|
||||
|
||||
/** @brief Vendor-specific error. */
|
||||
kSDIOReturnVendorError = 0x408,
|
||||
|
||||
/** @brief Device in reset. */
|
||||
kSDIOReturnInReset = 0x409,
|
||||
|
||||
/** @brief Block never signaled command complete. */
|
||||
kSDIOReturnNoCmdComplete = 0x40A,
|
||||
|
||||
/** @brief Block never signaled transfer complete. */
|
||||
kSDIOReturnNoTransferComplete = 0x40B,
|
||||
|
||||
/** @brief DMA transfer timed out. */
|
||||
kSDIOReturnDMATimeout = 0x40C,
|
||||
|
||||
|
||||
// Card Errors
|
||||
|
||||
/** @brief General Card Error. */
|
||||
kSDIOReturnCardError = 0x500,
|
||||
|
||||
/** @brief Failed because no card is inserted. */
|
||||
kSDIOReturnNoCard = 0x501,
|
||||
|
||||
/** @brief Failed because the card was ejected. */
|
||||
kSDIOReturnCardEjected = 0x502,
|
||||
|
||||
/** @brief Failed because card is write protected. */
|
||||
kSDIOReturnWriteProtected = 0x503,
|
||||
|
||||
|
||||
// Problems on SDIO Command Line
|
||||
|
||||
/** @brief General SDIO Cmd line error. */
|
||||
kSDIOReturnCmdError = 0x600,
|
||||
|
||||
/** @brief SDIO Cmd line is busy. */
|
||||
kSDIOReturnCmdLineBusy = 0x601,
|
||||
|
||||
/** @brief SDIO Cmd line's signal level is incorrect. */
|
||||
kSDIOReturnCmdSignalInvalid = 0x602,
|
||||
|
||||
/** @brief Command index error in response. */
|
||||
kSDIOReturnCmdIndexError = 0x603,
|
||||
|
||||
/** @brief Conflict on SDIO Command Line. */
|
||||
kSDIOReturnCmdLineConflict = 0x604,
|
||||
|
||||
/** @brief SDIO Cmd failed with a CRC error. */
|
||||
kSDIOReturnCmdCRCError = 0x605,
|
||||
|
||||
/** @brief SDIO Cmd failed with a End Bit error. */
|
||||
kSDIOReturnCmdEndBitError = 0x606,
|
||||
|
||||
/** @brief SDIO Cmd Timed out (no response. */
|
||||
kSDIOReturnCmdTimeout = 0x607,
|
||||
|
||||
|
||||
// Problems on SDIO Data Line
|
||||
|
||||
/** @brief General SDIO Data Line Error. */
|
||||
kSDIOReturnDataError = 0x700,
|
||||
|
||||
/** @brief SDIO Data line is busy. */
|
||||
kSDIOReturnDataLineBusy = 0x701,
|
||||
|
||||
/** @brief SDIO Data line's signal level is incorrect. */
|
||||
kSDIOReturnDataSignalInvalid = 0x702,
|
||||
|
||||
/** @brief SDIO Data failed with a CRC error. */
|
||||
kSDIOReturnDataCRCError = 0x703,
|
||||
|
||||
/** @brief SDIO Data failed with a CRC error. */
|
||||
kSDIOReturnDataEndBitError = 0x704,
|
||||
|
||||
/** @brief SDIO Data Timed out (no response. */
|
||||
kSDIOReturnDataTimeout = 0x705,
|
||||
};
|
||||
|
||||
typedef enum SDIOReturn SDIOReturn_t;
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SDIO_TYPES_H_ */
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include "sdiodrv_command.h"
|
||||
|
||||
#include <sys/task.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <AssertMacros.h>
|
||||
|
||||
#include "sdiocommon/sdhc_debug.h"
|
||||
#include "sdiocommon/sdio_cmdprop.h"
|
||||
#include "sdiodrv_config.h"
|
||||
|
||||
|
||||
|
||||
#define CMD_INHIBITED_CHECKS (20)
|
||||
#define CMD_INHIBITED_WAIT (5)
|
||||
#define DATA_INHIBITED_CHECKS (20)
|
||||
#define DATA_INHIBITED_WAIT (5)
|
||||
#define COMMAND_COMPLETE_CHECKS (1000)
|
||||
|
||||
|
||||
static SDIOReturn_t
|
||||
sdiodrv_prepareCommand(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
if(sdhc_isCommandInhibitedOnCmd(sdhc)) {
|
||||
dprintf(DEBUG_CRITICAL, "SDHC @ %p: Command inhibited!\n", sdhc);
|
||||
|
||||
for(unsigned int i=0; sdhc_isCommandInhibitedOnCmd(sdhc) && i < CMD_INHIBITED_CHECKS; i++) {
|
||||
task_sleep(CMD_INHIBITED_WAIT);
|
||||
}
|
||||
|
||||
if(sdhc_isCommandInhibitedOnCmd(sdhc)) {
|
||||
return kSDIOReturnCmdLineBusy;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle busy and abort
|
||||
/* if(issueWithBusy && !issueAbortCommand) {
|
||||
if(sdhc_isCommandInhibitedOnData(sdhc)) {
|
||||
dprintf(DEBUG_CRITICAL, "SDHC @ %p: Data inhibited!\n", sdhc);
|
||||
|
||||
for(unsigned int i=0; sdhc_isCommandInhibitedOnData(sdhc) && i < DATA_INHIBITED_CHECKS; i++) {
|
||||
task_sleep(DATA_INHIBITED_WAIT);
|
||||
}
|
||||
|
||||
if(sdhc_isCommandInhibitedOnData(sdhc)) {
|
||||
return kSDIOReturnDataLineBusy;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return kSDIOReturnSuccess;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static SDIOReturn_t
|
||||
sdiodrv_completeCommand(SDHCRegisters_t *sdhc, struct SDIOCommandResponse *response)
|
||||
{
|
||||
SDIOReturn_t retval = sdhc_getCommandStatus(sdhc);
|
||||
|
||||
if(kSDIOReturnSuccess != retval) {
|
||||
dprintf(DEBUG_CRITICAL, "%s: SDIO Cmd Failed (0x%X): cmd = 0x%X, arg = 0x%X, resp0 = 0x%X, normalInt = 0x%X, errorInt = 0x%X, state = 0x%X\n", __func__,
|
||||
retval, sdhc->command, sdhc->argument, sdhc->response[0],
|
||||
sdhc->normalInterruptStatus, sdhc->errorInterruptStatus, sdhc->presentState);
|
||||
|
||||
sdiodrv_resetSDHC(sdhc, kSDHCResetCmdLine);
|
||||
}
|
||||
|
||||
sdhc_clearCommandStatus(sdhc);
|
||||
|
||||
sdhc_copyCommandResponse(sdhc, response);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDIOReturn_t
|
||||
sdiodrv_sendSDIOCommand(SDHCRegisters_t *sdhc,
|
||||
const struct SDIOCommand *command,
|
||||
struct SDIOCommandResponse *response)
|
||||
{
|
||||
check(command);
|
||||
|
||||
return sdiodrv_sendCommand(sdhc, command->index, command->argument, response);
|
||||
}
|
||||
|
||||
SDIOReturn_t
|
||||
sdiodrv_sendCommand(SDHCRegisters_t *sdhc, UInt16 commandIndex, UInt32 commandArg, struct SDIOCommandResponse *response)
|
||||
{
|
||||
check(sdhc);
|
||||
check(response);
|
||||
|
||||
SDIOReturn_t retval = sdiodrv_prepareCommand(sdhc);
|
||||
if(kSDIOReturnSuccess != retval) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
sdhc->argument = commandArg;
|
||||
|
||||
UInt16 command = sdio_generateCommand(commandIndex);
|
||||
|
||||
// dprintf(DEBUG_INFO, "%s: cmd = 0x%04X, arg = 0x%08X\n", __func__,
|
||||
// command, sdhc->argument);
|
||||
// sdhc_dumpRegisterFile(sdhc);
|
||||
|
||||
sdhc->command = command;
|
||||
|
||||
for(unsigned int i=0; !sdhc_isCommandComplete(sdhc); i++) {
|
||||
if(i >= COMMAND_COMPLETE_CHECKS) {
|
||||
dprintf(DEBUG_CRITICAL, "%s: No command complete after %u checks: cmd = 0x%X, arg = 0x%X, normalInt = 0x%X, errorInt = 0x%X, state = 0x%X\n",
|
||||
__func__, COMMAND_COMPLETE_CHECKS,
|
||||
sdhc->command, sdhc->argument,
|
||||
sdhc->normalInterruptStatus, sdhc->errorInterruptStatus, sdhc->presentState);
|
||||
|
||||
sdiodrv_resetSDHC(sdhc, kSDHCResetCmdLine);
|
||||
|
||||
return kSDIOReturnNoCmdComplete;
|
||||
}
|
||||
|
||||
task_yield();
|
||||
}
|
||||
|
||||
retval = sdiodrv_completeCommand(sdhc, response);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SDIODRV_COMMAND_H
|
||||
#define _SDIODRV_COMMAND_H
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sdiocommon/sdhc_registers.h>
|
||||
|
||||
|
||||
struct SDIOCommand;
|
||||
struct SDIOCommandResponse;
|
||||
|
||||
/** @brief Sends an SDIO Command.
|
||||
* @param[in] sdhc
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in] commandIndex
|
||||
* The number of the command to perform.
|
||||
* @param[in] commandArg
|
||||
* The command argument.
|
||||
* @param[out] response
|
||||
* The response to the SDIO command.
|
||||
* @return
|
||||
* kSDIOReturnSuccess - on success
|
||||
* kSDIOReturnCmdLineBusy - Command line already in use
|
||||
* kSDIOReturnNoCmdComplete - Command complete status never set in SDHC
|
||||
* kSDIOReturnCmdLineConflict - Line voltage doesn't match what was driven
|
||||
* kSDIOReturnCmdTimeout - SDHC timed out waiting for command response
|
||||
* kSDIOReturnCmdCRCError - SDHC detected a CRC error in command
|
||||
* kSDIOReturnCmdEndBitError - SDHC detected an end-bit error in command
|
||||
* kSDIOReturnCmdIndexError - Command index in response doesn't match request
|
||||
*/
|
||||
SDIOReturn_t sdiodrv_sendCommand(SDHCRegisters_t *sdhc,
|
||||
UInt16 commandIndex,
|
||||
UInt32 commandArg,
|
||||
struct SDIOCommandResponse *response);
|
||||
|
||||
/** @brief Sends an SDIO Command.
|
||||
* @param[in] sdhc
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in] command
|
||||
* The command parameters.
|
||||
* @param[out] response
|
||||
* The response to the SDIO command.
|
||||
* @return
|
||||
* kSDIOReturnSuccess - on success
|
||||
* kSDIOReturnCmdLineBusy - Command line already in use
|
||||
* kSDIOReturnNoCmdComplete - Command complete status never set in SDHC
|
||||
* kSDIOReturnCmdLineConflict - Line voltage doesn't match what was driven
|
||||
* kSDIOReturnCmdTimeout - SDHC timed out waiting for command response
|
||||
* kSDIOReturnCmdCRCError - SDHC detected a CRC error in command
|
||||
* kSDIOReturnCmdEndBitError - SDHC detected an end-bit error in command
|
||||
* kSDIOReturnCmdIndexError - Command index in response doesn't match request
|
||||
*/
|
||||
SDIOReturn_t sdiodrv_sendSDIOCommand(SDHCRegisters_t *sdhc,
|
||||
const struct SDIOCommand *command,
|
||||
struct SDIOCommandResponse *response);
|
||||
|
||||
|
||||
#endif /* _SDIODRV_COMMAND_H */
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include "sdiodrv_config.h"
|
||||
|
||||
#include <sys/task.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <AssertMacros.h>
|
||||
|
||||
|
||||
/** Wait this long after a Command / Data reset is triggered before continuing.
|
||||
* Allows time for the reset to propogate to the SDIO side of the hardware block.
|
||||
* Value chosen to ensure that at least 4 SD Clock periods pass at the lowest
|
||||
* expected SD Clock rate. 4 clock periods @ 10 KHz = 400 us
|
||||
* See: <rdar://problem/6676702> SDIO: Soft Reset not propagated until SD clock running
|
||||
*/
|
||||
#define RESET_WAIT_US (400)
|
||||
|
||||
|
||||
/** The maximum SD Clock rate clients are allowed to set.
|
||||
* The maximum SD Clock rate allowed by the standard is 50 MHz. However,
|
||||
* The Arasan block is rated to support up to a 52 MHz clock. Allow clients
|
||||
* to set rates up to the higher max:
|
||||
* <rdar://problem/7091999> Arasan SDIO Driver should allow up to 52 MHz SD Clock
|
||||
*/
|
||||
static const IOSDIOClockRate kMaxAllowableSDClockRate = 52000000;
|
||||
|
||||
|
||||
static bool
|
||||
sdiodrv_waitForInternalClk(const SDHCRegisters_t *sdhc)
|
||||
{
|
||||
for (int i = 0; i < 10 && !sdhc_isInternalClockStable(sdhc); i++) {
|
||||
task_sleep(5);
|
||||
}
|
||||
|
||||
return sdhc_isInternalClockStable(sdhc);
|
||||
}
|
||||
|
||||
|
||||
static SDIOReturn_t
|
||||
sdiodrv_enableClocks(SDHCRegisters_t *sdhc)
|
||||
{
|
||||
sdhc_enableInternalClock(sdhc, true);
|
||||
|
||||
if(!sdiodrv_waitForInternalClk(sdhc)) {
|
||||
return kSDIOReturnInternalClockUnstable;
|
||||
}
|
||||
|
||||
sdhc_enableSDClock(sdhc, true);
|
||||
|
||||
return kSDIOReturnSuccess;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sdiodrv_disableClocks(SDHCRegisters_t *sdhc)
|
||||
{
|
||||
sdhc_enableSDClock(sdhc, false);
|
||||
//sdhc_enableInternalClock(sdhc, false);
|
||||
}
|
||||
|
||||
IOSDIOClockRate
|
||||
sdiodrv_setClockRate(SDHCRegisters_t *sdhc, IOSDIOClockRate *targetSDClkRateHz, UInt32 inputClkRateHz)
|
||||
{
|
||||
check(sdhc);
|
||||
check(targetSDClkRateHz);
|
||||
check(*targetSDClkRateHz > 0 && *targetSDClkRateHz <= kMaxAllowableSDClockRate);
|
||||
check(inputClkRateHz);
|
||||
|
||||
if(*targetSDClkRateHz <= 0 || *targetSDClkRateHz > kMaxAllowableSDClockRate || !inputClkRateHz) {
|
||||
return kSDIOReturnBadArgument;
|
||||
}
|
||||
|
||||
bool sdClkEnabled = sdhc_isSDClockEnabled(sdhc);
|
||||
|
||||
sdhc_enableSDClock(sdhc, false);
|
||||
|
||||
IOSDIOClockRate newRate = sdhc_setClockDividerRate(sdhc, *targetSDClkRateHz, inputClkRateHz);
|
||||
|
||||
if(sdClkEnabled && !sdiodrv_waitForInternalClk(sdhc)) {
|
||||
*targetSDClkRateHz = 0;
|
||||
return kSDIOReturnInternalClockUnstable;
|
||||
}
|
||||
|
||||
sdhc_setDataTimeoutCounter(sdhc);
|
||||
|
||||
sdhc_enableSDClock(sdhc, sdClkEnabled);
|
||||
|
||||
*targetSDClkRateHz = newRate;
|
||||
return kSDIOReturnSuccess;
|
||||
}
|
||||
|
||||
SDIOReturn_t
|
||||
sdiodrv_resetSDHC(SDHCRegisters_t *sdhc, SDHCResetFlags_t resetOptions)
|
||||
{
|
||||
check(sdhc);
|
||||
check(resetOptions & (kSDHCResetDataLine | kSDHCResetCmdLine | kSDHCResetAll));
|
||||
|
||||
if(!(resetOptions & (kSDHCResetDataLine | kSDHCResetCmdLine | kSDHCResetAll))) {
|
||||
return kSDIOReturnBadArgument;
|
||||
}
|
||||
|
||||
dprintf(DEBUG_INFO, "%s: Resetting SDHC @ %p, 0x%X\n", __func__, sdhc, resetOptions);
|
||||
sdhc_reset(sdhc, resetOptions);
|
||||
|
||||
for (int i = 0; i < 100 && sdhc_isResetting(sdhc); i++) {
|
||||
task_sleep(5);
|
||||
}
|
||||
|
||||
if(sdhc_isResetting(sdhc)) {
|
||||
dprintf(DEBUG_CRITICAL, "%s: Failed to complete reset, 0x%X\n", __func__, sdhc->softwareReset);
|
||||
return kSDIOReturnInReset;
|
||||
}
|
||||
|
||||
// <rdar://problem/6676702> SDIO: Soft Reset not propagated until SD clock running
|
||||
if(resetOptions & kSDHCResetAll) {
|
||||
// If we're doing a full reset, enable the internal clock to ensure
|
||||
// that the reset is propogated into the SDIO domain
|
||||
sdhc_enableInternalClock(sdhc, true);
|
||||
if(!sdiodrv_waitForInternalClk(sdhc)) {
|
||||
return kSDIOReturnInternalClockUnstable;
|
||||
}
|
||||
|
||||
} else {
|
||||
// If we're not doing a full reset, wait for >= 4 SD Clock periods
|
||||
task_sleep(RESET_WAIT_US);
|
||||
}
|
||||
|
||||
return kSDIOReturnSuccess;
|
||||
}
|
||||
|
||||
SDIOReturn_t
|
||||
sdiodrv_setClockMode(SDHCRegisters_t *sdhc, enum IOSDIOClockMode clockMode)
|
||||
{
|
||||
check(sdhc);
|
||||
check(kIOSDIO1BitMode == busWidth || kIOSDIO4BitMode == busWidth);
|
||||
|
||||
SDIOReturn_t retval = kSDIOReturnSuccess;
|
||||
|
||||
switch(clockMode)
|
||||
{
|
||||
case kIOSDIOClockOff:
|
||||
sdiodrv_disableClocks(sdhc);
|
||||
break;
|
||||
case kIOSDIOClockOn:
|
||||
retval = sdiodrv_enableClocks(sdhc);
|
||||
break;
|
||||
default:
|
||||
retval = kSDIOReturnBadArgument;
|
||||
break;
|
||||
};
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDIOReturn_t
|
||||
sdiodrv_setBusWidth(SDHCRegisters_t *sdhc, enum IOSDIOBusWidth busWidth)
|
||||
{
|
||||
check(sdhc);
|
||||
check(kIOSDIO1BitMode == busWidth || kIOSDIO4BitMode == busWidth);
|
||||
|
||||
SDIOReturn_t retval = kSDIOReturnSuccess;
|
||||
|
||||
switch(busWidth)
|
||||
{
|
||||
case kIOSDIO1BitMode:
|
||||
case kIOSDIO4BitMode:
|
||||
sdhc_setDataTransferWidth(sdhc, busWidth);
|
||||
break;
|
||||
default:
|
||||
retval = kSDIOReturnBadArgument;
|
||||
break;
|
||||
};
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
SDIOReturn_t
|
||||
sdiodrv_setBusSpeedMode(SDHCRegisters_t *sdhc, enum IOSDIOBusSpeedMode speedMode)
|
||||
{
|
||||
check(sdhc);
|
||||
check(kIOSDIONormalSpeed == speedMode || kIOSDIOHighSpeed == speedMode);
|
||||
|
||||
SDIOReturn_t retval = kSDIOReturnSuccess;
|
||||
|
||||
switch(speedMode)
|
||||
{
|
||||
case kIOSDIONormalSpeed:
|
||||
sdhc_setHighSpeedMode(sdhc, false);
|
||||
break;
|
||||
case kIOSDIOHighSpeed:
|
||||
check(sdhc_isHighSpeedSupported(sdhc));
|
||||
sdhc_setHighSpeedMode(sdhc, true);
|
||||
break;
|
||||
default:
|
||||
retval = kSDIOReturnBadArgument;
|
||||
break;
|
||||
};
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SDIODRV_CONFIG_H
|
||||
#define _SDIODRV_CONFIG_H
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sdiocommon/sdhc_registers.h>
|
||||
#include <sdiocommon/sdio_types.h>
|
||||
|
||||
/** @brief Resets the SDIO Host Controller
|
||||
* @param[in] sdhc
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in] resetOptions
|
||||
* Flags identifying what to reset
|
||||
* @return
|
||||
* kSDIOReturnSuccess - on success
|
||||
* kSDIOReturnBadArgument - unsupported flag set
|
||||
* kSDIOReturnInReset - SDHC didn't come out of reset in a resonable time period
|
||||
*/
|
||||
SDIOReturn_t sdiodrv_resetSDHC(SDHCRegisters_t *sdhc, SDHCResetFlags_t resetOptions);
|
||||
|
||||
/** @brief Sets the SD Clock rate.
|
||||
* @param[in] sdhc
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in,out] targetSDClkRateHz
|
||||
* Desired SD Clock rate, in Hz
|
||||
* On exit set to the actual clock rate set in Hz, 0 on error.
|
||||
* @param[in] inputClkRateHz
|
||||
* SDHC Block's input clock rate, in Hz. Used to derive SD Clock.
|
||||
* @return
|
||||
* kSDIOReturnSuccess - on success
|
||||
* kSDIOReturnBadArgument - Illegal target or base rate
|
||||
* kSDIOReturnInternalClockUnstable - Block's internal clock didn't stabilize in a reasonable time period
|
||||
*/
|
||||
SDIOReturn_t sdiodrv_setClockRate(SDHCRegisters_t *sdhc, IOSDIOClockRate *targetSDClkRateHz, UInt32 inputClkRateHz);
|
||||
|
||||
/** @brief Enable / disable the SD Clock.
|
||||
* @param[in] sdhc
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in] clockMode
|
||||
* Whether to turn on or turn off the clock.
|
||||
* @return
|
||||
* kSDIOReturnSuccess - on success
|
||||
* kSDIOReturnBadArgument - Unsupported clock mode
|
||||
* kSDIOReturnInternalClockUnstable - Block's internal clock didn't stabilize in a reasonable time period
|
||||
*/
|
||||
SDIOReturn_t sdiodrv_setClockMode(SDHCRegisters_t *sdhc, enum IOSDIOClockMode clockMode);
|
||||
|
||||
/** @brief Set the width of the data bus (# of data lines).
|
||||
* @param[in] sdhc
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in] busWidth
|
||||
* Whether to transfer data in 1 or 4 bit mode.
|
||||
* @return
|
||||
* kSDIOReturnSuccess - on success
|
||||
* kSDIOReturnBadArgument - Unsupported bus width
|
||||
*/
|
||||
SDIOReturn_t sdiodrv_setBusWidth(SDHCRegisters_t *sdhc, enum IOSDIOBusWidth busWidth);
|
||||
|
||||
/** @brief Set the bus speed used by the Host Controller.
|
||||
* @param[in] sdhc
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in] speedMode
|
||||
* Whether to transfer data in low or high speed mode.
|
||||
* @return
|
||||
* kSDIOReturnSuccess - on success
|
||||
* kSDIOReturnBadArgument - Unsupported speed mode
|
||||
*/
|
||||
SDIOReturn_t sdiodrv_setBusSpeedMode(SDHCRegisters_t *sdhc, enum IOSDIOBusSpeedMode speedMode);
|
||||
|
||||
|
||||
#endif /* _SDIODRV_CONFIG_H */
|
||||
|
||||
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include "sdiodrv_transfer.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include <AssertMacros.h>
|
||||
|
||||
#include <sys/task.h>
|
||||
#include <drivers/dma.h>
|
||||
#include <platform.h>
|
||||
|
||||
#include <platform/soc/hwdmachannels.h>
|
||||
#include <platform/soc/hwclocks.h>
|
||||
#include <platform/clocks.h>
|
||||
|
||||
#include "sdiodrv_config.h"
|
||||
#include "sdiodrv_command.h"
|
||||
|
||||
|
||||
#define TRANSFER_COMPLETE_CHECKS (1000)
|
||||
|
||||
#define DMA_WORD_SIZE (4)
|
||||
#define DMA_BURST_SIZE (8)
|
||||
|
||||
#define DMA_WORKAROUND_PRESENT (1)
|
||||
|
||||
|
||||
static SDIOReturn_t
|
||||
sdiodrv_prepareTransfer(SDHCRegisters_t *sdhc, const struct SDIOTransfer *transfer)
|
||||
{
|
||||
check(sdhc_getMaxBlockLength(sdhc) < transfer->blockSize);
|
||||
|
||||
sdhc_setBlockSize(sdhc, transfer->blockSize);
|
||||
|
||||
sdhc->blockCount = transfer->blockCount;
|
||||
|
||||
UInt16 transferMode = kSDIOTransferEnableBlockCount | kSDIOTransferEnableDMA;
|
||||
|
||||
if(sdhc->blockCount > 1) {
|
||||
transferMode |= kSDIOTransferMultipleBlocks;
|
||||
}
|
||||
|
||||
if(transfer->direction & kSDIODirectionRead) {
|
||||
transferMode |= kSDIOTransferReadFromCard;
|
||||
}
|
||||
|
||||
sdhc->transferMode = transferMode;
|
||||
|
||||
// dprintf(DEBUG_INFO, "\n%s: blockSize = %u, blockCount = %u, cmd53ItemCount = %u, cmd53BlkMode = 0x%X, mode = 0x%X\n", __func__,
|
||||
// transfer->blockSize, transfer->blockCount,
|
||||
// (0x1FF & transfer->command.argument), ((1 << 27) & transfer->command.argument), transferMode);
|
||||
|
||||
return kSDIOReturnSuccess;
|
||||
}
|
||||
|
||||
static SDIOReturn_t
|
||||
sdiodrv_completeTransfer(SDHCRegisters_t *sdhc, const struct SDIOTransfer *transfer)
|
||||
{
|
||||
SDIOReturn_t retval = sdhc_getTransferStatus(sdhc);
|
||||
|
||||
if(kSDIOReturnSuccess != retval) {
|
||||
dprintf(DEBUG_CRITICAL, "%s: SDIO Transfer Failed (0x%X): cmd = 0x%X, blkSize = %u, blkCount = %u / %u, normalInt = 0x%X, errorInt = 0x%X, state = 0x%X\n",
|
||||
__func__, retval,
|
||||
sdhc->command,
|
||||
transfer->blockSize, sdhc->blockCount, transfer->blockCount,
|
||||
sdhc->normalInterruptStatus, sdhc->errorInterruptStatus, sdhc->presentState);
|
||||
|
||||
sdiodrv_resetSDHC(sdhc, kSDHCResetDataLine);
|
||||
}
|
||||
|
||||
sdhc_clearTransferStatus(sdhc);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
sdiodrv_logSegments(const struct dma_segment *segment, UInt32 numSegments, UInt32 totalSize)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "%s: numSegments = %u, totalSize = %u\n", __func__,
|
||||
numSegments, totalSize);
|
||||
for (unsigned int i = 0; i < numSegments; i++) {
|
||||
dprintf(DEBUG_INFO, "%s: segment[%u] @ %p: paddr = 0x%X, len = %u\n", __func__,
|
||||
i, &segment[i], segment[i].paddr, segment[i].length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @brief Adjusts a segment in the list such that the first N segments sum to the block size.
|
||||
*
|
||||
* @param[in] segmentList
|
||||
* The segment list
|
||||
* @param[in] numSegments
|
||||
* how many segments are in the segment list.
|
||||
* @param[in] blockSize
|
||||
* the target blocksize
|
||||
* @param[out] origLength
|
||||
* Original length of the returned segment
|
||||
* @return
|
||||
* a pointer to the adjusted segment, NULL if no adjustment occured
|
||||
*/
|
||||
static struct dma_segment*
|
||||
sdiodrv_adjustSegment(struct dma_segment *segmentList, UInt32 numSegments, UInt32 blockSize, UInt32 *origLength)
|
||||
{
|
||||
UInt32 byteCount=0;
|
||||
|
||||
for(UInt32 i = 0; i < numSegments; i++) {
|
||||
// If the # bytes in the segments sums evenly to blockSize, no adjustment needed
|
||||
if(byteCount == blockSize) {
|
||||
// dprintf(DEBUG_INFO, "%s: no adjustment needed: byteCount = %u, blockSize = %u\n", __func__, byteCount, blockSize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
byteCount += segmentList[i].length;
|
||||
|
||||
// Need to adjust this segment
|
||||
if(byteCount > blockSize) {
|
||||
*origLength = segmentList[i].length;
|
||||
UInt32 overage = byteCount - blockSize;
|
||||
segmentList[i].length -= overage;
|
||||
// dprintf(DEBUG_INFO, "%s: adjusting: byteCount = %u, blockSize = %u, overage = %u\n", __func__, byteCount, blockSize, overage);
|
||||
return &segmentList[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** @brief Readjusts a segment back to its original length. */
|
||||
static void
|
||||
sdiodrv_readjustSegment(struct dma_segment *segment, UInt32 origLength)
|
||||
{
|
||||
if(!segment) {
|
||||
return;
|
||||
}
|
||||
|
||||
// dprintf(DEBUG_INFO, "%s: readjusting: origLength = %u\n", __func__, origLength);
|
||||
segment->length = origLength;
|
||||
}
|
||||
|
||||
/** @brief Advance the segment list to the item byteOffset bytes in.
|
||||
*
|
||||
* Note: This function makes no effort to enforce aligmnment of the output segments.
|
||||
* However, if the input segments are aligned and the byte offset is a multiple of
|
||||
* the aligment, the output segments will be aligned.
|
||||
*
|
||||
* @param[in] segmentList
|
||||
* The segment list
|
||||
* @param[in,out] segmentsRemaining
|
||||
* On input: how many segments are in the segment list.
|
||||
* On output: how many segments are in the returned list
|
||||
* @param[in] byteOffset
|
||||
* How many bytes into the segment list the new head should be
|
||||
* @return
|
||||
* the new head of the segment list, NULL if there isn't a segment at the requested byte offset
|
||||
*/
|
||||
static struct dma_segment*
|
||||
sdiodrv_advanceSegList(struct dma_segment *segmentList, UInt32 *segmentsRemaining, UInt32 byteOffset)
|
||||
{
|
||||
const UInt32 numSegments = *segmentsRemaining;
|
||||
UInt32 byteCount=0;
|
||||
|
||||
for(UInt32 i = 0; i < numSegments; i++) {
|
||||
// If the current item is the right offset in
|
||||
if(byteCount == byteOffset) {
|
||||
// dprintf(DEBUG_INFO, "%s: correct offset: byteCount = %u, byteOffset = %u\n", __func__, byteCount, byteOffset);
|
||||
return &segmentList[i];
|
||||
}
|
||||
|
||||
byteCount += segmentList[i].length;
|
||||
|
||||
// If the offset puts us somewhere inside the current segment
|
||||
if(byteCount > byteOffset) {
|
||||
// Adjust the segment to the right offset and return as the new head
|
||||
UInt32 overage = byteCount - byteOffset;
|
||||
UInt32 segOffset = segmentList[i].length - overage;
|
||||
// dprintf(DEBUG_INFO, "%s: updating: byteCount = %u, byteOffset = %u, overage = %u, segOffset = %u\n", __func__, byteCount, byteOffset, overage, segOffset);
|
||||
|
||||
segmentList[i].paddr += segOffset;
|
||||
segmentList[i].length -= segOffset;
|
||||
|
||||
return &segmentList[i];
|
||||
}
|
||||
(*segmentsRemaining)--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
sdiodrv_performCacheOperation(int operation, void *address, u_int32_t length)
|
||||
{
|
||||
// Adjust the address / length so that it is aligned on a cacheline
|
||||
void *adjustedAddr = (void*)((u_int32_t)address & ~(CPU_CACHELINE_SIZE-1));
|
||||
u_int32_t adjustedLength = length + (address - adjustedAddr);
|
||||
|
||||
adjustedLength = (adjustedLength + (CPU_CACHELINE_SIZE-1)) & ~(CPU_CACHELINE_SIZE-1);
|
||||
|
||||
// dprintf(DEBUG_INFO, "%s: op = 0x%X, addr = %p, length = %u\n", __func__, operation, adjustedAddr, adjustedLength);
|
||||
|
||||
platform_cache_operation(operation, adjustedAddr, adjustedLength);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sdiodrv_handleDMAComplete(void *arg)
|
||||
{
|
||||
struct task_event *dmaCompleteEvent = (struct task_event *)arg;
|
||||
|
||||
// dprintf(DEBUG_INFO, "%s: DMA Complete %p\n", __func__, dmaCompleteEvent);
|
||||
|
||||
event_signal(dmaCompleteEvent);
|
||||
}
|
||||
|
||||
static SDIOReturn_t
|
||||
sdiodrv_performDMA(SDHCRegisters_t *sdhc,
|
||||
const struct SDIOTransfer *transfer,
|
||||
const struct SDIOMemorySegments *memory,
|
||||
struct task_event *dmaCompleteEvent)
|
||||
{
|
||||
bool dmaRead = transfer->direction & kSDIODirectionRead;
|
||||
u_int32_t dmaCommand = (dmaRead ? DMA_CMD_DIR_RX : DMA_CMD_DIR_TX);
|
||||
int dmaErr;
|
||||
|
||||
|
||||
#if DMA_WORKAROUND_PRESENT
|
||||
|
||||
// dprintf(DEBUG_INFO, "%s: starting dma for block %u\n", __func__, 0);
|
||||
dmaErr = dma_execute_async(dmaCommand, DMA_SDIO,
|
||||
(struct dma_segment*)memory->segmentList, (void*)&sdhc->bufferDataPort, memory->dataLength,
|
||||
DMA_WORD_SIZE, DMA_BURST_SIZE,
|
||||
&sdiodrv_handleDMAComplete, dmaCompleteEvent);
|
||||
if(dmaErr) {
|
||||
dprintf(DEBUG_CRITICAL, "%s: DMA %s failure (%d), %u / %u blocks of size %u remain (%u seg @ %p)\n",
|
||||
__func__, (dmaRead ? "read" : "write"), dmaErr,
|
||||
sdhc->blockCount, transfer->blockCount, transfer->blockSize,
|
||||
memory->segmentCount, memory->segmentList);
|
||||
sdiodrv_logSegments((struct dma_segment *)memory->segmentList, memory->segmentCount, memory->dataLength);
|
||||
return kSDIOReturnADMAError;
|
||||
}
|
||||
|
||||
// dprintf(DEBUG_INFO, "%s: waiting on block %u\n", __func__, 0);
|
||||
bool signaled = event_wait_timeout(dmaCompleteEvent, DMA_SDIO_TIMEOUT_US);
|
||||
if(!signaled) {
|
||||
dprintf(DEBUG_INFO, "%s: Timeout on DMA %s, %u / %u blocks of size %u remain (%u seg @ %p)\n",
|
||||
__func__, (dmaRead ? "read" : "write"),
|
||||
sdhc->blockCount, transfer->blockCount, transfer->blockSize,
|
||||
memory->segmentCount, memory->segmentList);
|
||||
sdiodrv_logSegments((struct dma_segment *)memory->segmentList, memory->segmentCount, memory->dataLength);
|
||||
|
||||
// <rdar://problem/7304920> iBoot IOP SDIO Driver doesn't complete transfer after DMA Timeout
|
||||
SDIOReturn_t transferStatus = sdiodrv_completeTransfer(sdhc, transfer);
|
||||
if(kSDIOReturnSuccess == transferStatus) {
|
||||
transferStatus = kSDIOReturnDMATimeout;
|
||||
}
|
||||
|
||||
// Save & restore the interrupt config across SDHC reset
|
||||
// Fix "No SDIO Cmd Complete" errors after "SDIO Data CRC Error"
|
||||
// <rdar://problem/10646932> 9B139: devices lost ability to use WiFi
|
||||
UInt16 normalInterruptStatusEnable = sdhc->normalInterruptStatusEnable;
|
||||
UInt16 normalInterruptSignalEnable = sdhc->normalInterruptSignalEnable;
|
||||
UInt16 errorInterruptStatusEnable = sdhc->errorInterruptStatusEnable;
|
||||
UInt16 errorInterruptSignalEnable = sdhc->errorInterruptSignalEnable;
|
||||
|
||||
|
||||
// <rdar://problem/7311911> H2A/H3 CDMA - DMA Hang after SDIO CMD53 Rx Data CRC Error
|
||||
// Hard-reset SDIO block before resetting CDMA
|
||||
clock_reset_device(CLK_SDIO);
|
||||
|
||||
dma_cancel(DMA_SDIO);
|
||||
|
||||
sdhc->normalInterruptStatusEnable = normalInterruptStatusEnable;
|
||||
sdhc->normalInterruptSignalEnable = normalInterruptSignalEnable;
|
||||
sdhc->errorInterruptStatusEnable = errorInterruptStatusEnable;
|
||||
sdhc->errorInterruptSignalEnable = errorInterruptSignalEnable;
|
||||
|
||||
return transferStatus;
|
||||
}
|
||||
|
||||
// dprintf(DEBUG_INFO, "%s: END, signaled = %u, err = 0x%X\n", __func__, signaled, sdhc->errorInterruptStatus);
|
||||
|
||||
|
||||
#else
|
||||
|
||||
struct dma_segment *blkSegmentList = (struct dma_segment*)memory->segmentList;
|
||||
UInt32 segmentsRemaining = memory->segmentCount;
|
||||
struct dma_segment *adjustedSegment = NULL;
|
||||
UInt32 origLength = 0;
|
||||
|
||||
// We have to setup a new DMA for each SDIO block. Yuck.
|
||||
for(UInt32 b = 0; b < transfer->blockCount && blkSegmentList; b++) {
|
||||
|
||||
sdiodrv_performCacheOperation(CACHE_CLEAN, blkSegmentList, sizeof(blkSegmentList[0]));
|
||||
|
||||
adjustedSegment = sdiodrv_adjustSegment(blkSegmentList, segmentsRemaining, transfer->blockSize, &origLength);
|
||||
if(adjustedSegment) {
|
||||
sdiodrv_performCacheOperation(CACHE_CLEAN, adjustedSegment, sizeof(*adjustedSegment));
|
||||
}
|
||||
|
||||
// sdiodrv_logSegments((struct dma_segment *)blkSegmentList, segmentsRemaining, transfer->blockSize);
|
||||
// dprintf(DEBUG_INFO, "%s: block[%u] @ %p: paddr = 0x%X, len = %u\n", __func__,
|
||||
// b, &blkSegmentList[0], blkSegmentList[0].paddr, blkSegmentList[0].length);
|
||||
|
||||
dmaErr = dma_execute_async(dmaCommand, DMA_SDIO,
|
||||
blkSegmentList, (void*)&sdhc->bufferDataPort, transfer->blockSize,
|
||||
DMA_WORD_SIZE, DMA_BURST_SIZE,
|
||||
&sdiodrv_handleDMAComplete, dmaCompleteEvent);
|
||||
|
||||
if(dmaErr) {
|
||||
dprintf(DEBUG_CRITICAL, "%s: DMA %s failure (%d) on block %u of size %u (%u segRem @ %p)\n", __func__,
|
||||
(dmaRead ? "read" : "write"), dmaErr, b, transfer->blockSize,
|
||||
segmentsRemaining, blkSegmentList);
|
||||
sdiodrv_logSegments((struct dma_segment *)blkSegmentList, segmentsRemaining, memory->dataLength);
|
||||
return kSDIOReturnADMAError;
|
||||
}
|
||||
|
||||
|
||||
// dprintf(DEBUG_INFO, "%s: waiting on block %u\n", __func__, b);
|
||||
bool signaled = event_wait_timeout(dmaCompleteEvent, DMA_SDIO_TIMEOUT_US);
|
||||
if(!signaled) {
|
||||
dprintf(DEBUG_INFO, "%s: Timeout on DMA %s, block %u of size %u (%u segRem @ %p)\n", __func__,
|
||||
(dmaRead ? "read" : "write"), b, transfer->blockSize,
|
||||
segmentsRemaining, blkSegmentList);
|
||||
sdiodrv_logSegments((struct dma_segment *)blkSegmentList, segmentsRemaining, memory->dataLength);
|
||||
|
||||
// <rdar://problem/7304920> iBoot IOP SDIO Driver doesn't complete transfer after DMA Timeout
|
||||
SDIOReturn_t transferStatus = sdiodrv_completeTransfer(sdhc, transfer);
|
||||
if(kSDIOReturnSuccess == transferStatus) {
|
||||
transferStatus = kSDIOReturnDMATimeout;
|
||||
}
|
||||
|
||||
// Save & restore the interrupt config across SDHC reset
|
||||
// Fix "No SDIO Cmd Complete" errors after "SDIO Data CRC Error"
|
||||
// <rdar://problem/10646932> 9B139: devices lost ability to use WiFi
|
||||
UInt16 normalInterruptStatusEnable = sdhc->normalInterruptStatusEnable;
|
||||
UInt16 normalInterruptSignalEnable = sdhc->normalInterruptSignalEnable;
|
||||
UInt16 errorInterruptStatusEnable = sdhc->errorInterruptStatusEnable;
|
||||
UInt16 errorInterruptSignalEnable = sdhc->errorInterruptSignalEnable;
|
||||
|
||||
|
||||
// <rdar://problem/7311911> H2A/H3 CDMA - DMA Hang after SDIO CMD53 Rx Data CRC Error
|
||||
// Hard-reset SDIO block before resetting CDMA
|
||||
clock_reset_device(CLK_SDIO);
|
||||
|
||||
dma_cancel(DMA_SDIO);
|
||||
|
||||
sdhc->normalInterruptStatusEnable = normalInterruptStatusEnable;
|
||||
sdhc->normalInterruptSignalEnable = normalInterruptSignalEnable;
|
||||
sdhc->errorInterruptStatusEnable = errorInterruptStatusEnable;
|
||||
sdhc->errorInterruptSignalEnable = errorInterruptSignalEnable;
|
||||
|
||||
return transferStatus;
|
||||
}
|
||||
|
||||
sdiodrv_readjustSegment(adjustedSegment, origLength);
|
||||
|
||||
blkSegmentList = sdiodrv_advanceSegList(blkSegmentList, &segmentsRemaining, transfer->blockSize);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return kSDIOReturnSuccess;
|
||||
}
|
||||
|
||||
|
||||
SDIOReturn_t
|
||||
sdiodrv_transferData(SDHCRegisters_t *sdhc,
|
||||
const struct SDIOTransfer *transfer,
|
||||
const struct SDIOMemorySegments *memory,
|
||||
struct SDIOCommandResponse *response,
|
||||
struct task_event *dmaCompleteEvent)
|
||||
{
|
||||
check(sdhc);
|
||||
check(transfer);
|
||||
check(memory);
|
||||
check(response);
|
||||
check(dmaCompleteEvent);
|
||||
check(transfer->direction);
|
||||
check((transfer->direction & (kSDIODirectionRead | kSDIODirectionWrite)) != (kSDIODirectionRead | kSDIODirectionWrite));
|
||||
check(transfer->blockCount);
|
||||
check(transfer->blockSize);
|
||||
check(memory->dataLength);
|
||||
check(memory->segmentCount);
|
||||
check(memory->segmentList);
|
||||
|
||||
|
||||
// Prepare the SDHC for the transfer
|
||||
SDIOReturn_t retval = sdiodrv_prepareTransfer(sdhc, transfer);
|
||||
if(kSDIOReturnSuccess != retval) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Send the SDIO Command
|
||||
retval = sdiodrv_sendSDIOCommand(sdhc, &transfer->command, response);
|
||||
if(kSDIOReturnSuccess != retval) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
// TODO: PIO Mode support?
|
||||
|
||||
// Kick off the DMA
|
||||
retval = sdiodrv_performDMA(sdhc, transfer, memory, dmaCompleteEvent);
|
||||
if(kSDIOReturnSuccess != retval) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Wait until the Host Controller says the transfer is complete
|
||||
// Should be done by the time the DMA / PIO is done
|
||||
for(unsigned int i=0; !sdhc_isTransferComplete(sdhc); i++) {
|
||||
if(i >= TRANSFER_COMPLETE_CHECKS) {
|
||||
dprintf(DEBUG_CRITICAL, "%s: No (%s) transfer complete after %u checks: cmd = 0x%X, blkSize = %u, blkCount = %u / %u, normalInt = 0x%X, errorInt = 0x%X, state = 0x%X\n",
|
||||
__func__, ((transfer->direction & kSDIODirectionRead) ? "read" : "write"), TRANSFER_COMPLETE_CHECKS,
|
||||
sdhc->command,
|
||||
transfer->blockSize, sdhc->blockCount, transfer->blockCount,
|
||||
sdhc->normalInterruptStatus, sdhc->errorInterruptStatus, sdhc->presentState);
|
||||
|
||||
sdiodrv_resetSDHC(sdhc, kSDHCResetDataLine);
|
||||
|
||||
if(kSDIOReturnSuccess == retval) {
|
||||
retval = kSDIOReturnNoTransferComplete;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
task_yield();
|
||||
}
|
||||
|
||||
// Get the transfer status and cleanup the SDHC
|
||||
SDIOReturn_t transferStatus = sdiodrv_completeTransfer(sdhc, transfer);
|
||||
|
||||
// Note: on transfer error the SDHC block needs to be reset to workaround:
|
||||
//<rdar://problem/6413326> H2: Workaround stuck dmacbreq on SW Reset DAT
|
||||
// We'll let the AP-side of the SDIO driver do this for now, since it has
|
||||
// the state needed to restore the block to an operational state.
|
||||
// TODO: <rdar://problem/7312019> Move hardware workarounds into IOP SDIO driver
|
||||
|
||||
return kSDIOReturnSuccess == transferStatus ? retval : transferStatus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SDIODRV_TRANSFER_H
|
||||
#define _SDIODRV_TRANSFER_H
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sdiocommon/sdhc_registers.h>
|
||||
|
||||
struct SDIOTransfer;
|
||||
struct SDIOMemorySegments;
|
||||
struct SDIOCommandResponse;
|
||||
struct task_event;
|
||||
|
||||
|
||||
/** @brief Transfers Data across the SDIO bus.
|
||||
* @param[in] sdhc
|
||||
* Target SDIO Host Controller.
|
||||
* @param[in] transfer
|
||||
* Information describing the transfer to perform
|
||||
* @param[in] memory
|
||||
* Information describing the memory that will source/sink the transfer.
|
||||
* (Includes the segment list)
|
||||
* @param[out] response
|
||||
* The response to the SDIO command associated with the data transfer
|
||||
* @param[in] dmaCompleteEvent
|
||||
* The DMA event used to synchronize the DMA transfer
|
||||
* @return
|
||||
* kSDIOReturnSuccess - on success
|
||||
* kSDIOReturnADMAError - Error executing the DMA
|
||||
* kSDIOReturnDMATimeout - DMA failed to complete
|
||||
* kSDIOReturnNoTransferComplete - Transfer complete status never set in SDHC
|
||||
* kSDIOReturnDataTimeout - SDHC timed out waiting for data
|
||||
* kSDIOReturnDataCRCError - SDHC detected a CRC error in data
|
||||
* kSDIOReturnDataEndBitError - SDHC detected an end-bit error in data
|
||||
*/
|
||||
SDIOReturn_t sdiodrv_transferData(SDHCRegisters_t *sdhc,
|
||||
const struct SDIOTransfer *transfer,
|
||||
const struct SDIOMemorySegments *memory,
|
||||
struct SDIOCommandResponse *response,
|
||||
struct task_event *dmaCompleteEvent);
|
||||
|
||||
|
||||
#endif /* _SDIODRV_TRANSFER_H */
|
||||
|
||||
Reference in new issue
Block a user