diff options
Diffstat (limited to 'arch/arm/mach-tegra/nvddk/nvddk_sdio.c')
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_sdio.c | 3285 |
1 files changed, 0 insertions, 3285 deletions
diff --git a/arch/arm/mach-tegra/nvddk/nvddk_sdio.c b/arch/arm/mach-tegra/nvddk/nvddk_sdio.c deleted file mode 100644 index 3f51dbe9b1a2..000000000000 --- a/arch/arm/mach-tegra/nvddk/nvddk_sdio.c +++ /dev/null @@ -1,3285 +0,0 @@ -/* - * Copyright (c) 2007-2009 NVIDIA Corporation. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NVIDIA Corporation nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -/** - * @file - * @brief <b>NVIDIA Driver Development Kit: - * NvDDK SDIO Driver Implementation</b> - * - * @b Description: Implementation of the NvDDK SDIO API. - * - */ - -#include "nvddk_sdio.h" -#include "ap20/arsdmmc.h" -#include "ap20/arclk_rst.h" -#include "nvrm_drf.h" -#include "nvrm_hardware_access.h" -#include "nvodm_query_pinmux.h" -#include "nvrm_interrupt.h" -#include "nvassert.h" -#include "nvrm_memmgr.h" -#include "nvrm_pinmux.h" -#include "nvos.h" -#include "nvodm_pmu.h" -#include "nvodm_query_discovery.h" -#include "nvodm_query_gpio.h" -#include "nvrm_pmu.h" -#include "nvodm_sdio.h" -#include "nvodm_query.h" - -#define ENABLE_DEBUG_PRINTS 0 - -#if ENABLE_DEBUG_PRINTS -#define SD_PRINT(x) NvOsDebugPrintf x -#else -#define SD_PRINT(x) -#endif - -// Macro to get expression for modulo value that is power of 2 -// Expression: DIVIDEND % (pow(2, Log2X)) -#define MACRO_MOD_LOG2NUM(DIVIDEND, Log2X) \ - ((DIVIDEND) & ((1 << (Log2X)) - 1)) - -// Macro to get expression for multiply by number which is power of 2 -// Expression: VAL * (1 << Log2Num) -#define MACRO_POW2_LOG2NUM(Log2Num) \ - (1 << (Log2Num)) - -// Macro to get expression for multiply by number which is power of 2 -// Expression: VAL * (1 << Log2Num) -#define MACRO_MULT_POW2_LOG2NUM(VAL, Log2Num) \ - ((VAL) << (Log2Num)) - -// Macro to get expression for div by number that is power of 2 -// Expression: VAL / (1 << Log2Num) -#define MACRO_DIV_POW2_LOG2NUM(VAL, Log2Num) \ - ((VAL) >> (Log2Num)) - -// The sdio controller needs a delay of 500 AHB clock cycles after -// the soft reset. Assuming the minimum AHB clock frequency as 10MHz, -// 500 AHB clock cycles will be equivalent to 50 USec. (refer Bug ID: 334872) -#define SDMMC_SOFT_RESET_DELAY_USEC 50 - -// Semaphore timeout for the sdio abort -#define NVDDK_SDMMC_ABORT_TIMEOUT_MSEC 10 - -// Delay required while doing sdio abort as per HW bug #371685. -#define SDMMC_ABORT_DELAY_USEC 2000 - -#define SDMMC_DMA_BUFFER_SIZE \ - SDMMC_BLOCK_SIZE_BLOCK_COUNT_0_HOST_DMA_BUFFER_SIZE_DMA16K -#define SDMMC_DMA_TRANSFER_SIZE (1 << (12 + SDMMC_DMA_BUFFER_SIZE)) - -// Size of the memory buffer size -#define SDMMC_MEMORY_BUFFER_SIZE ((SDMMC_DMA_TRANSFER_SIZE) * (2)) - -// Maximum sdio transfer size using polling method -#define SDMMC_MAX_POLLING_SIZE 4096 - -// Maximum polling time for completing the sdio transfer -#define SDMMC_MIN_POLLING_TIME_USEC 1500000 - -// Mmc erase command and timeout -#define MMC_ERASE_COMMAND 38 -#define MMC_ERASE_COMMAND_MIN_POLLING_TIME_USEC 10000000 - - -// Polling size(1MB) for timeout calculation -#define SDMMC_TIMEOUT_CALCULATION_SIZE (1024*1024) -// Delay between polling the interrupt status register -#define SDMMC_POLLING_DELAY_USEC 50 - -#define SDMMC_ERROR_STATUS_VALUE 0xFFFF0000 -#define SDMMC_DEBOUNCE_TIME_MS 5 - -/* Minimum system frequency of 100MHz used in case of busy hints */ -#define SDMMC_HW_MIN_SYSTEM_FREQ_KH 100000 -#define SDMMC_EMC_MIN_SYSTEM_FREQ_KH 166000 - -// Frequency of the sdio controller when sdio controller is suspended -#define SDMMC_LOW_POWER_FREQ_KHZ 100 - -// Enable the following flag to enable the read busy hints. -#define ENABLE_READ_BUSY_HINTS 0 - -// Delay after issuing the abort -#define NVDDK_SDMMC_DELAY_AFTER_ABORT_USEC 40 -// sdio interrupts used by the driver -#define SDIO_INTERRUPTS 0x7F000F -// sdio error interrupts -#define SDIO_ERROR_INTERRUPTS 0x7F0000 - - -//Sdio command errors -#define SDIO_CMD_ERROR_INTERRUPTS 0xF0000 -#define SDMMC_MAX_NUMBER_OF_BLOCKS 65536 - -enum -{ - SdioNormalModeMinFreq = 100, // 100Khz - SdioNormalModeMaxFreq = 25000, // 25Mhz - SdioHighSpeedModeMaxFreq = 52000 -}; - -enum { SDMMC_INTERNAL_CLOCK_TIMEOUT_STEP_USEC = 10 }; -enum { SDMMC_INTERNAL_CLOCK_TIMEOUT_USEC = 100 }; - -enum { SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_STEP_USEC = 10 }; -enum { SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_USEC = 100 }; - -enum { SW_CONTROLLER_BUSY_TIMEOUT_STEP_USEC = 10 }; -enum { SW_CONTROLLER_BUSY_TIMEOUT_USEC = 1000 }; - -enum -{ - SDMMC_MAX_BLOCK_SIZE_512 = 512, - SDMMC_MAX_BLOCK_SIZE_1024 = 1024, - SDMMC_MAX_BLOCK_SIZE_2048 = 2048 -}; - -// Defines various MMC card specific command types - -#define SDMMC_REGR(pSdioHwRegsVirtBaseAdd, reg) \ - NV_READ32((pSdioHwRegsVirtBaseAdd) + ((SDMMC_##reg##_0)/4)) - -#define SDMMC_REGW(pSdioHwRegsVirtBaseAdd, reg, val) \ - do\ - {\ - NV_WRITE32((((pSdioHwRegsVirtBaseAdd) + ((SDMMC_##reg##_0)/4))), (val));\ - }while (0) - #define DIFF_FREQ(x, y) \ - (x>y)?(x-y):(y-x) - -enum { SDMMC_ENABLE_ALL_INTERRUPTS = 0x000000FF }; - -#define NVDDK_SDMMC_COMMAND_TIMEOUT_MSEC 1000 -#define NVDDK_SDMMC_DATA_TIMEOUT_MSEC 1000 - -/** - * @brief Contains the sdio instance details . This information is shared - * between the thread and the isr - */ -typedef struct NvDdkSdioInfoRec -{ - // Nvrm device handle - NvRmDeviceHandle hRm; - // Instance of the SDMMC module - NvU32 Instance; - // SDMMC configuration pin-map. - NvOdmSdioPinMap PinMap; - // Physical base address of the specific sdio instance - NvRmPhysAddr SdioPhysicalAddress; - // Virtual base address of the specific sdio instance - NvU32* pSdioVirtualAddress; - // size of the sdio register map - NvU32 SdioBankSize; - /** - * @brief Semaphore to signal any notification to the sdio client modules. - * The notifications include error conditions, Command complete, - * read/write transfer complete, card related events etc. - * The client is supposed to call the NvDdkSdioGetAsyncStatus API after - * receiving a notification, to get the details of a particular event. - */ - NvOsSemaphoreHandle NotificationSema; - /** Card insertion/removal semaphore handle received from the client */ - NvOsSemaphoreHandle CardEventsSema; - NvRmGpioHandle hGpio; - // Bus width - NvU32 BusWidth; - // Bus voltage - NvU32 BusVoltage; - // High speed mode - NvU32 IsHighSpeedEnabled; - // Clock frequency - NvRmFreqKHz ConfiguredFrequency; - // flag to indicate sd memory or sdio mode - NvBool IsAcceptCardEvents; - // Indicates whether it is a read or a write transaction - NvBool IsRead; - // Request Type - SdioRequestType RequestType; - // Semaphore handle used for internal handshaking between the calling thread - // and the isr - NvOsSemaphoreHandle PrivSdioSema; - // Rmmemory Handle of the buffer allocated - NvRmMemHandle hRmMemHandle; - // Physical Buffer Address of the memory - NvU32 pPhysBuffer; - // Virtual Buffer Address - void* pVirtBuffer; - // Interrupt handle - NvRmGpioInterruptHandle GpioIntrHandle; - NvDdkSdioStatus* ControllerStatus; - NvRmGpioPinHandle WriteProtectPin; - NvRmGpioPinHandle CardDetectPin; - NvOsSemaphoreHandle SdioPowerMgtSema; - NvU32 SdioRmPowerClientId; - const NvOdmGpioPinInfo *GpioPinInfo; - // Maximum block size supported by the controller - NvU32 MaxBlockLength; - NvOdmSdioHandle SdioOdmHandle; - NvOsInterruptHandle InterruptHandle; - NvBool ISControllerSuspended; - NvBool IsSdControllerVersion2; - NvOsIntrMutexHandle SdioThreadSafetyMutex; -}NvDdkSdioInfo; - -typedef enum -{ - // data time out frequency = TMCLK/8K - SdioDataTimeout_COUNTER_8K = 0, - // data time out frequency = TMCLK/16K - SdioDataTimeout_COUNTER_16K, - // data time out frequency = TMCLK/32K - SdioDataTimeout_COUNTER_32K, - // data time out frequency = TMCLK/64K - SdioDataTimeout_COUNTER_64K, - // data time out frequency = TMCLK/128K - SdioDataTimeout_COUNTER_128K, - // data time out frequency = TMCLK/256K - SdioDataTimeout_COUNTER_256K, - // data time out frequency = TMCLK/512K - SdioDataTimeout_COUNTER_512K, - // data time out frequency = TMCLK/1M - SdioDataTimeout_COUNTER_1M, - // data time out frequency = TMCLK/2M - SdioDataTimeout_COUNTER_2M, - // data time out frequency = TMCLK/4M - SdioDataTimeout_COUNTER_4M, - // data time out frequency = TMCLK/8M - SdioDataTimeout_COUNTER_8M, - // data time out frequency = TMCLK/16M - SdioDataTimeout_COUNTER_16M, - // data time out frequency = TMCLK/32M - SdioDataTimeout_COUNTER_32M, - // data time out frequency = TMCLK/64M - SdioDataTimeout_COUNTER_64M, - // data time out frequency = TMCLK/128M - SdioDataTimeout_COUNTER_128M, - // data time out frequency = TMCLK/256M - SdioDataTimeout_COUNTER_256M -}SdioDataTimeout; - -// This is the default block size set whenever the nvddk sdio driver is open -enum { SDMMC_DEFAULT_BLOCK_SIZE = 512 }; - -static NvBool SdioEnableInternalClock(NvDdkSdioDeviceHandle hSdio); -static NvBool SdioIsReset(NvDdkSdioDeviceHandle hSdio); -static NvError SdioEnableBusPower(NvDdkSdioDeviceHandle hSdio); -static void ConfigureInterrupts(NvDdkSdioDeviceHandle hSdio, NvU32 IntrEnableMask, NvU32 IntrDisableMask, NvU32 IntrStatusEnableMask); -static void PrivSdioAbort(NvDdkSdioDeviceHandle hSdio); -void PrivSdioErrorRecovery(NvDdkSdioDeviceHandle hSdio); -NvError SdioEnableCardClock(NvDdkSdioDeviceHandle hSdio, NvBool IsEnable); - -static NvError -SdioSetSlotClockRate( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioClkDivider Divider); - -static NvError - SdioSetDataTimeout( - NvDdkSdioDeviceHandle hSdio, - SdioDataTimeout SdioDataToCounter); - -static NvU32 -SdioIsControllerBusy( - NvDdkSdioDeviceHandle hSdio, - NvBool IsDataCommand); -static NvError -SdioRegisterInterrupts( - NvRmDeviceHandle hRm, - NvDdkSdioDeviceHandle hSdio); - -static void SdioIsr(void* args); - -static void GpioInterruptHandler(void *arg); - -NvError SdioConfigureCardClock(NvDdkSdioDeviceHandle hSdio, NvBool IsEnable); - -NvError - SdioGetPhysAdd( - NvRmDeviceHandle hRmDevice, - NvRmMemHandle* hRmMemHandle, - void** pVirtBuffer, - NvU32 size, - NvU32* pPhysBuffer); - -static NvError SdioBlockTransfer( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfRWBytes, - NvU32 pReadBuffer, - NvDdkSdioCommand *pRWRequest, - NvBool HWAutoCMD12Enable, - NvBool IsRead); - -static NvError -PrivSdioPollingRead( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfBytesToRead, - void *pReadBuffer, - NvDdkSdioCommand *pRWCommand, - NvBool HWAutoCMD12Enable, - NvU32* SdioStatus); - -static NvError -PrivSdioPollingWrite( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfBytesToWrite, - void *pWriteBuffer, - NvDdkSdioCommand *pRWCommand, - NvBool HWAutoCMD12Enable, - NvU32* SdioStatus); - -void PrivSdioReset(NvDdkSdioDeviceHandle hSdio); - -NvError -PrivSdioSendCommandPolling( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioCommand *pCommand, - NvU32* SdioStatus); - -void -PrivSdioGetCaps( - NvRmDeviceHandle hDevice, - NvDdkSdioHostCapabilities *pHostCap, - NvU32 instance); - -// function to check power of 2 -static NvBool -UtilCheckPowerOf2(NvU32 Num) -{ - // A power of 2 satisfies condition (N & (N - 1)) == (2 * N - 1) - if ((Num & (Num - 1)) == 0) - return NV_TRUE; - else - return NV_FALSE; -} - -// Simple function to get log2, assumed value power of 2, else return -// returns log2 of immediately smaller number -NvU8 -SdUtilGetLog2(NvU32 Val) -{ - NvU8 Log2Val = 0; - NvU32 i; - // Value should be non-zero - NV_ASSERT(Val > 0); - if (UtilCheckPowerOf2(Val) == NV_FALSE) - { - NvOsDebugPrintf("\nCalling simple log2 with value which is " - "not power of 2 "); - // In case of values that are not power of 2 we return the - // integer part of the result of log2 - } - // Value is power of 2 - if (Val > 0) - { - // Assumed that Val is NvU32 - for (i = 0; i < 32; i++) - { - // divide by 2 - Val = MACRO_DIV_POW2_LOG2NUM(Val, 1); - if (Val == 0) - { - // Return 0 when Val is 1 - break; - } - Log2Val++; - } - } - return Log2Val; -} - - - -NvError NvDdkSdioOpen( - NvRmDeviceHandle hDevice, - NvRmGpioHandle hGpio, - NvDdkSdioDeviceHandle *phSdio, - NvOsSemaphoreHandle *pNotificationSema, - NvOsSemaphoreHandle *pCardEventsSema, - NvU8 Instance) -{ - - NvError e = NvSuccess; - NvBool IsReset = NV_TRUE; - NvBool IsClkStable = NV_FALSE; - NvDdkSdioDeviceHandle hSdio = NULL; - NvRmFreqKHz pConfiguredFrequencyKHz = 0; - NvDdkSdioStatus* ControllerStatus = NULL; - NvU32 val = 0; - NvU32 capabilities = 0; - NvU32 MaxInstances = 0; - NvBool IsCardInserted = NV_TRUE; - NvDdkSdioHostCapabilities HostCap; - -#if !NV_OAL - NvU32 PinCount = 0; - NvOsInterruptHandler IntrHandler = (NvOsInterruptHandler)GpioInterruptHandler; - - NV_ASSERT(hGpio); -#endif - - NV_ASSERT(pNotificationSema); - NV_ASSERT(pCardEventsSema); - - MaxInstances = NvRmModuleGetNumInstances(hDevice, NvRmModuleID_Sdio); - // Validate the instance number - if (Instance >= MaxInstances) - { - return NvError_SdioInstanceTaken; - } - - if (NvRmSetModuleTristate(hDevice, - NVRM_MODULE_ID(NvRmModuleID_Sdio,Instance), NV_FALSE)!=NvSuccess) - return NvError_NotSupported; - - hSdio = NvOsAlloc(sizeof(NvDdkSdioInfo)); - - if (!hSdio) - { - return NvError_InsufficientMemory; - } - - NvOsMemset(hSdio, 0, sizeof(NvDdkSdioInfo)); - - // initialise the members of the NvDdkSdioDeviceHandle struct - hSdio->hRm = hDevice; - hSdio->Instance = Instance; - hSdio->NotificationSema = *pNotificationSema; - hSdio->ConfiguredFrequency = SdioNormalModeMinFreq; - hSdio->CardEventsSema = *pCardEventsSema; - hSdio->IsSdControllerVersion2 = NV_FALSE; - hSdio->ISControllerSuspended = NV_FALSE; - - NvRmModuleGetBaseAddress( - hDevice, - NVRM_MODULE_ID(NvRmModuleID_Sdio, Instance), - &hSdio->SdioPhysicalAddress, - &hSdio->SdioBankSize); - - NV_CHECK_ERROR_CLEANUP(NvRmPhysicalMemMap( - hSdio->SdioPhysicalAddress, - hSdio->SdioBankSize, NVOS_MEM_READ_WRITE, - NvOsMemAttribute_Uncached, - (void **)&hSdio->pSdioVirtualAddress)); - - ControllerStatus = NvOsAlloc(sizeof(NvDdkSdioStatus)); - if (NULL == ControllerStatus) - { - e = NvError_InsufficientMemory; - goto fail; - } - - e = NvOsIntrMutexCreate(&hSdio->SdioThreadSafetyMutex); - if (e != NvError_Success) - { - goto fail; - } - - ControllerStatus->SDControllerStatus = NvDdkSdioCommandStatus_None; - ControllerStatus->SDErrorStatus = NvDdkSdioError_None; - hSdio->ControllerStatus = ControllerStatus; - - // Event sema to register with the rm_power module - NV_CHECK_ERROR_CLEANUP(NvOsSemaphoreCreate(&hSdio->PrivSdioSema, 0)); - - // Event sema to register with the rm_power module - NV_CHECK_ERROR_CLEANUP(NvOsSemaphoreCreate(&hSdio->SdioPowerMgtSema, 0)); - - // register with the rm_power manager - hSdio->SdioRmPowerClientId = NVRM_POWER_CLIENT_TAG('S','D','I','O'); - NV_CHECK_ERROR_CLEANUP(NvRmPowerRegister(hSdio->hRm, - hSdio->SdioPowerMgtSema, - &hSdio->SdioRmPowerClientId)); - - hSdio->SdioOdmHandle = NvOdmSdioOpen(Instance); - if (!hSdio->SdioOdmHandle) - { - e = NvError_NotSupported; - goto fail; - } - - // enable power - NV_CHECK_ERROR_CLEANUP(NvRmPowerVoltageControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, Instance), - hSdio->SdioRmPowerClientId, - NvRmVoltsUnspecified, - NvRmVoltsUnspecified, - NULL, - 0, - NULL)); - - // now enable clock to sdio controller - NV_CHECK_ERROR_CLEANUP(NvRmPowerModuleClockControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, Instance), - hSdio->SdioRmPowerClientId, - NV_TRUE)); - - - - // reset controller - NvRmModuleReset(hSdio->hRm, NVRM_MODULE_ID(NvRmModuleID_Sdio, Instance)); - - IsReset = SdioIsReset(hSdio); - if (IsReset != NV_TRUE) - { - goto fail; - } - - // enable internal clock to sdio - IsClkStable = SdioEnableInternalClock(hSdio); - if (IsClkStable != NV_TRUE) - { - goto fail; - } - - // Configure the clock frequency - NV_CHECK_ERROR_CLEANUP(NvDdkSdioSetClockFrequency(hSdio, - hSdio->ConfiguredFrequency, - &pConfiguredFrequencyKHz)); - - PrivSdioGetCaps(hDevice, &HostCap, Instance); - hSdio->IsSdControllerVersion2 = HostCap.IsSdControllerVersion2; - - capabilities = SDMMC_REGR(hSdio->pSdioVirtualAddress, CAPABILITIES); - val = NV_DRF_VAL(SDMMC, CAPABILITIES, MAX_BLOCK_LENGTH, capabilities); - switch (val) - { - case SDMMC_CAPABILITIES_0_MAX_BLOCK_LENGTH_BYTE512: - hSdio->MaxBlockLength = SDMMC_MAX_BLOCK_SIZE_512; - break; - - case SDMMC_CAPABILITIES_0_MAX_BLOCK_LENGTH_BYTE1024: - hSdio->MaxBlockLength = SDMMC_MAX_BLOCK_SIZE_1024; - break; - - case SDMMC_CAPABILITIES_0_MAX_BLOCK_LENGTH_BYTE2048: - hSdio->MaxBlockLength = SDMMC_MAX_BLOCK_SIZE_2048; - break; - - default: - hSdio->MaxBlockLength = SDMMC_DEFAULT_BLOCK_SIZE; - break; - } - HostCap.MaxBlockLength = hSdio->MaxBlockLength; - - // Set the block size - NvDdkSdioSetBlocksize(hSdio, SDMMC_DEFAULT_BLOCK_SIZE); - - val = NV_DRF_VAL(SDMMC, CAPABILITIES, VOLTAGE_SUPPORT_3_3_V, capabilities); - if (val) - { - HostCap.BusVoltage = NvDdkSdioSDBusVoltage_3_3; - } - else - { - val = NV_DRF_VAL(SDMMC, CAPABILITIES, VOLTAGE_SUPPORT_3_0_V, capabilities); - if (val) - { - HostCap.BusVoltage = NvDdkSdioSDBusVoltage_3_0; - } - else - { - val = NV_DRF_VAL(SDMMC, CAPABILITIES, VOLTAGE_SUPPORT_1_8_V, capabilities); - if (val) - { - HostCap.BusVoltage = NvDdkSdioSDBusVoltage_1_8; - } - else - { - // Invalid bus voltage - NV_ASSERT(0); - } - } - } - - // set sd bus voltage - NvDdkSdioSetSDBusVoltage(hSdio, HostCap.BusVoltage); - - - // enable sd bus power - SdioEnableBusPower(hSdio); - - // set data timeout counter value - SdioSetDataTimeout(hSdio, SdioDataTimeout_COUNTER_128M); - - // register interrupt handler - NV_CHECK_ERROR_CLEANUP(SdioRegisterInterrupts(hDevice, hSdio)); - -#if !NV_OAL - hSdio->hGpio = hGpio; - - hSdio->GpioPinInfo = NvOdmQueryGpioPinMap(NvOdmGpioPinGroup_Sdio, - hSdio->Instance, &PinCount); - - if (hSdio->GpioPinInfo != NULL) - { - // Check whether the write protect gpio pin is supported or not - if (PinCount == 1) - { - NvRmGpioAcquirePinHandle(hGpio, hSdio->GpioPinInfo[0].Port, - hSdio->GpioPinInfo[0].Pin, &hSdio->CardDetectPin); - } - else if (PinCount == 2) - { - NvRmGpioAcquirePinHandle(hGpio, hSdio->GpioPinInfo[0].Port, - hSdio->GpioPinInfo[0].Pin, &hSdio->CardDetectPin); - - NvRmGpioAcquirePinHandle(hGpio, hSdio->GpioPinInfo[1].Port, - hSdio->GpioPinInfo[1].Pin, &hSdio->WriteProtectPin); - - NV_CHECK_ERROR_CLEANUP(NvRmGpioConfigPins(hGpio, &hSdio->WriteProtectPin, 1, - NvRmGpioPinMode_InputData)); - } - - e = NvRmGpioInterruptRegister(hGpio, hDevice, hSdio->CardDetectPin, - IntrHandler, NvRmGpioPinMode_InputInterruptAny, - hSdio, &hSdio->GpioIntrHandle, SDMMC_DEBOUNCE_TIME_MS); - if (e != NvError_Success) - { - goto fail; - } - - e = NvRmGpioInterruptEnable(hSdio->GpioIntrHandle); - if (e != NvError_Success) - { - goto fail; - } - } -#endif - - // Enable ALL important Normal interrupts - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, ~SDIO_INTERRUPTS, 0); - - - *phSdio = hSdio; - SdioConfigureCardClock(hSdio, NV_FALSE); - - // Allocate memory for sdio data transfers - NV_CHECK_ERROR_CLEANUP(SdioGetPhysAdd(hSdio->hRm, &hSdio->hRmMemHandle, - &hSdio->pVirtBuffer, SDMMC_MEMORY_BUFFER_SIZE, &hSdio->pPhysBuffer)); - - // Disable power to the slot if the card is not inserted - e = NvDdkSdioIsCardInserted(hSdio, &IsCardInserted); - if (e == NvSuccess) - { - if (!IsCardInserted) - { - NvOdmSdioSuspend(hSdio->SdioOdmHandle); - } - } - - return NvSuccess; - -fail: - NvOsIntrMutexDestroy(hSdio->SdioThreadSafetyMutex); - hSdio->SdioThreadSafetyMutex = NULL; - if (hSdio->SdioOdmHandle) - { - NvOdmSdioClose(hSdio->SdioOdmHandle); - } - - if (hSdio->hRmMemHandle != NULL) - { -#if !NV_OAL - NvRmMemUnmap(hSdio->hRmMemHandle, hSdio->pVirtBuffer, SDMMC_MEMORY_BUFFER_SIZE); -#endif - NvRmMemUnpin(hSdio->hRmMemHandle); - NvRmMemHandleFree(hSdio->hRmMemHandle); - } - - // disable power - NV_ASSERT_SUCCESS(NvRmPowerVoltageControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, Instance), - hSdio->SdioRmPowerClientId, - NvRmVoltsOff, - NvRmVoltsOff, - NULL, - 0, - NULL)); - - // unregister with the power manager - NvRmPowerUnRegister(hSdio->hRm, hSdio->SdioRmPowerClientId); - - // unregister/disable interrupt handler - NvRmInterruptUnregister(hDevice, hSdio->InterruptHandle); - hSdio->InterruptHandle = NULL; - - if (hSdio != NULL) - { - // destory the internal sdio abort semaphore - NvOsSemaphoreDestroy(hSdio->PrivSdioSema); - hSdio->PrivSdioSema = NULL; - - NvRmPhysicalMemUnmap(hSdio->pSdioVirtualAddress, hSdio->SdioBankSize); - } - - NvOsFree(ControllerStatus); - ControllerStatus = NULL; - hSdio->ControllerStatus = NULL; - NvOsSemaphoreDestroy(hSdio->SdioPowerMgtSema); - hSdio->SdioPowerMgtSema = NULL; - NvOsFree(hSdio); - hSdio = NULL; - *phSdio = NULL; - NV_ASSERT_SUCCESS(NvRmSetModuleTristate(hDevice, - NVRM_MODULE_ID(NvRmModuleID_Sdio,Instance), NV_TRUE)); - return e; -} - -NvError -NvDdkSdioSendCommand( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioCommand *pCommand, - NvU32* SdioStatus) -{ - NvU32 val = 0; - NvBool IsCrcCheckEnable = NV_FALSE; - NvBool IsIndexCheckEnable = NV_FALSE; - NvU32 IsControllerBusy = 0; - NvError status; - NvDdkSdioStatus* ControllerStatus = NULL; - - NV_ASSERT(hSdio); - NV_ASSERT(pCommand); - - ControllerStatus = hSdio->ControllerStatus; - - // clear the previous status if any - ControllerStatus->SDControllerStatus = NvDdkSdioCommandStatus_None; - ControllerStatus->SDErrorStatus = NvDdkSdioError_None; - hSdio->RequestType = NVDDK_SDIO_NORMAL_REQUEST; - -#if NV_OAL - status = PrivSdioSendCommandPolling(hSdio, pCommand, SdioStatus); - return status; -#endif - - // Commands with response type as R1b will generate transfer complete. - // Check if the command response is R1b. If the response is R1b we will get - // transfer complete interrupt. - if (pCommand->ResponseType == NvDdkSdioRespType_R1b && pCommand->CommandCode != 12) - { - // Disable command complete and enable transfer complete - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, NvDdkSdioCommandStatus_CommandComplete, 0); - } - else - { - // Enable command complete and disable transfer complete - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, NvDdkSdioCommandStatus_TransferComplete, 0); - } - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, CMD_XFER_MODE); - - // set the command number - val = NV_FLD_SET_DRF_NUM(SDMMC, CMD_XFER_MODE, COMMAND_INDEX, - pCommand->CommandCode, val); - - // check if any data transfer is involved in the command - val = NV_FLD_SET_DRF_NUM(SDMMC, CMD_XFER_MODE, DATA_PRESENT_SELECT, - pCommand->IsDataCommand, val); - val = NV_FLD_SET_DRF_NUM(SDMMC, CMD_XFER_MODE, COMMAND_TYPE, - pCommand->CommandType, val); - /* set the response type */ - switch (pCommand->ResponseType) - { - case NvDdkSdioRespType_NoResp: - IsCrcCheckEnable = NV_FALSE; - IsIndexCheckEnable = NV_FALSE; - val = NV_FLD_SET_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - NO_RESPONSE, val); - break; - - case NvDdkSdioRespType_R1: - case NvDdkSdioRespType_R5: - case NvDdkSdioRespType_R6: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_TRUE; - val = NV_FLD_SET_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48, val); - break; - - case NvDdkSdioRespType_R2: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_FALSE; - val = NV_FLD_SET_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_136, val); - break; - - case NvDdkSdioRespType_R3: - case NvDdkSdioRespType_R4: - IsCrcCheckEnable = NV_FALSE; - IsIndexCheckEnable = NV_FALSE; - val = NV_FLD_SET_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48, val); - break; - - case NvDdkSdioRespType_R1b: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_TRUE; - val = NV_FLD_SET_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48BUSY, val); - break; - - case NvDdkSdioRespType_R7: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_FALSE; - val = NV_FLD_SET_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48, val); - break; - - default: - NV_ASSERT(0); - } - - // set the is indexed - val = NV_FLD_SET_DRF_NUM(SDMMC, CMD_XFER_MODE, CMD_INDEX_CHECK_EN, - IsIndexCheckEnable, val); - - // set the is crc - val = NV_FLD_SET_DRF_NUM(SDMMC, CMD_XFER_MODE, CMD_CRC_CHECK_EN, - IsCrcCheckEnable, val); - - IsControllerBusy = SdioIsControllerBusy(hSdio, pCommand->IsDataCommand); - if (IsControllerBusy) - { - return NvError_SdioControllerBusy; - } - - // now write to the command argument register - SDMMC_REGW(hSdio->pSdioVirtualAddress, ARGUMENT, pCommand->CmdArgument); - - SdioConfigureCardClock(hSdio, NV_TRUE); - - // now write to the command xfer register - SDMMC_REGW(hSdio->pSdioVirtualAddress, CMD_XFER_MODE, val); - - status = NvOsSemaphoreWaitTimeout(hSdio->PrivSdioSema, NVDDK_SDMMC_COMMAND_TIMEOUT_MSEC); - - if (status == NvSuccess) - { - // if there is a Command timeout because of the previous command, reset CMD line - if (ControllerStatus->SDErrorStatus & NvDdkSdioError_CommandTimeout) - { - NvOsWaitUS(SDMMC_SOFT_RESET_DELAY_USEC); - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_DRF_VAL(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_CMD_LINE, val); - NV_ASSERT(val == 0); - } - - // if there is a data timeout because of the previous command, reset DAT line - if (ControllerStatus->SDErrorStatus & NvDdkSdioError_DataTimeout) - { - NvOsWaitUS(SDMMC_SOFT_RESET_DELAY_USEC); - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_DRF_VAL(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_DAT_LINE, val); - NV_ASSERT(val == 0); - } - } - - SdioConfigureCardClock(hSdio, NV_FALSE); - - *SdioStatus = ControllerStatus->SDErrorStatus; - return status; -} - -NvError -PrivSdioSendCommandPolling( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioCommand *pCommand, - NvU32* SdioStatus) -{ - NvU32 val = 0; - NvBool IsCrcCheckEnable = NV_FALSE; - NvBool IsIndexCheckEnable = NV_FALSE; - NvU32 IsControllerBusy = 0; - NvError status = NvSuccess; - NvDdkSdioStatus* ControllerStatus = NULL; - NvU32 PollTime = 0; - NvU32 TotalPollingTime = SDMMC_MIN_POLLING_TIME_USEC; - - if (pCommand->CommandCode == MMC_ERASE_COMMAND) - { - TotalPollingTime = MMC_ERASE_COMMAND_MIN_POLLING_TIME_USEC; - } - - NV_ASSERT(hSdio); - NV_ASSERT(pCommand); - - ControllerStatus = hSdio->ControllerStatus; - - // clear the previous status if any - ControllerStatus->SDControllerStatus = NvDdkSdioCommandStatus_None; - ControllerStatus->SDErrorStatus = NvDdkSdioError_None; - hSdio->RequestType = NVDDK_SDIO_NORMAL_REQUEST; - - // Commands with response type as R1b will generate transfer complete. - // Check if the command response is R1b. If the response is R1b we will get - // transfer complete interrupt. - // Commands with response type as R1b will generate transfer complete. - // Check if the command response is R1b. If the response is R1b we will get - // transfer complete interrupt. - if (pCommand->ResponseType == NvDdkSdioRespType_R1b && pCommand->CommandCode != 12) - { - // Disable all interrupts - ConfigureInterrupts(hSdio, 0, SDIO_INTERRUPTS, - (SDIO_ERROR_INTERRUPTS|NvDdkSdioCommandStatus_TransferComplete)); - } - else - { - // Enable command complete and disable transfer complete - ConfigureInterrupts(hSdio, 0, SDIO_INTERRUPTS, - (SDIO_ERROR_INTERRUPTS | NvDdkSdioCommandStatus_CommandComplete)); - } - - // set the command number - val |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, COMMAND_INDEX, - pCommand->CommandCode); - // check if any data transfer is involved in the command - val |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, DATA_PRESENT_SELECT, - pCommand->IsDataCommand); - val |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, COMMAND_TYPE, - pCommand->CommandType); - /* set the response type */ - switch (pCommand->ResponseType) - { - case NvDdkSdioRespType_NoResp: - IsCrcCheckEnable = NV_FALSE; - IsIndexCheckEnable = NV_FALSE; - val = NV_FLD_SET_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - NO_RESPONSE, val); - break; - - case NvDdkSdioRespType_R1: - case NvDdkSdioRespType_R5: - case NvDdkSdioRespType_R6: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_TRUE; - val |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48); - break; - - case NvDdkSdioRespType_R2: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_FALSE; - val |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_136); - break; - - case NvDdkSdioRespType_R3: - case NvDdkSdioRespType_R4: - IsCrcCheckEnable = NV_FALSE; - IsIndexCheckEnable = NV_FALSE; - val |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48); - break; - - case NvDdkSdioRespType_R1b: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_TRUE; - val |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48BUSY); - break; - - case NvDdkSdioRespType_R7: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_FALSE; - val |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48); - break; - - default: - NV_ASSERT(0); - } - - // set the is indexed - val |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, CMD_INDEX_CHECK_EN, - IsIndexCheckEnable); - - // set the is crc - val |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, CMD_CRC_CHECK_EN, - IsCrcCheckEnable); - - IsControllerBusy = SdioIsControllerBusy(hSdio, pCommand->IsDataCommand); - if (IsControllerBusy) - { - return NvError_SdioControllerBusy; - } - - *SdioStatus = NvDdkSdioError_None; - - // now write to the command argument register - SDMMC_REGW(hSdio->pSdioVirtualAddress, ARGUMENT, pCommand->CmdArgument); - - SdioConfigureCardClock(hSdio, NV_TRUE); - - // now write to the command xfer register - SDMMC_REGW(hSdio->pSdioVirtualAddress, CMD_XFER_MODE, val); - - // poll for the transfer or command complete interrupt - while (PollTime < TotalPollingTime) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS); - if (val & SDMMC_ERROR_STATUS_VALUE) - { - val &= SDMMC_ERROR_STATUS_VALUE; - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - *SdioStatus = val; - PrivSdioReset(hSdio); - status = NvSuccess; - break; - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, val)) - { - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, GEN_INT); - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - status = NvSuccess; - break; - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, CMD_COMPLETE, val)) - { - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, CMD_COMPLETE, GEN_INT); - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - status = NvSuccess; - break; - } - NvOsWaitUS(SDMMC_POLLING_DELAY_USEC); - PollTime += SDMMC_POLLING_DELAY_USEC; - } - if (PollTime >= TotalPollingTime) - { - PrivSdioReset(hSdio); - status = NvError_Timeout; - } - - SdioConfigureCardClock(hSdio, NV_FALSE); - return status; -} - -NvError -NvDdkSdioGetCommandResponse( - NvDdkSdioDeviceHandle hSdio, - NvU32 CommandNumber, - NvDdkSdioRespType ResponseType, - NvU32 *pResponse) -{ - NvU32 *pTemp; - - NV_ASSERT(hSdio); - NV_ASSERT(pResponse); - - pTemp = pResponse; - /* set the response type */ - switch (ResponseType) - { - case NvDdkSdioRespType_NoResp: - *pTemp = 0; - return NvSuccess; - - // SDMMC_RESP_LENGTH_48 - case NvDdkSdioRespType_R1: - case NvDdkSdioRespType_R1b: - case NvDdkSdioRespType_R3: - case NvDdkSdioRespType_R4: - case NvDdkSdioRespType_R5: - case NvDdkSdioRespType_R6: - case NvDdkSdioRespType_R7: - *pTemp = SDMMC_REGR(hSdio->pSdioVirtualAddress, RESPONSE_R0_R1); - *(++pTemp) = SDMMC_REGR(hSdio->pSdioVirtualAddress, RESPONSE_R2_R3); - break; - - // SDMMC_RESP_LENGTH_136 - case NvDdkSdioRespType_R2: - *pTemp = SDMMC_REGR(hSdio->pSdioVirtualAddress, RESPONSE_R0_R1); - *(++pTemp) = SDMMC_REGR(hSdio->pSdioVirtualAddress, RESPONSE_R2_R3); - *(++pTemp) = SDMMC_REGR(hSdio->pSdioVirtualAddress, RESPONSE_R4_R5); - *(++pTemp) = SDMMC_REGR(hSdio->pSdioVirtualAddress, RESPONSE_R6_R7); - break; - - default: - NV_ASSERT(0); - } - - return NvSuccess; -} - -static NvError -PrivSdioPollingRead( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfBytesToRead, - void *pReadBuffer, - NvDdkSdioCommand *pRWCommand, - NvBool HWAutoCMD12Enable, - NvU32* SdioStatus) -{ - NvU32 val = 0; - NvU32 PollTime = 0; - NvU8* VirtAddr = (NvU8*)hSdio->pVirtBuffer; - NvError Error = NvError_SdioReadFailed; - NvU32 BytesReceived = 0; - NvU32 BytesToBeCopied = 0; - NvU32 BytesToBeReceived = 0; - NvU8* ReadPtr = (NvU8*)pReadBuffer; - NvU32 PhysAddr = hSdio->pPhysBuffer; - NvBool IsTransferCompleted = NV_FALSE; - NvU32 IntrStatus = 0; - NvU32 PollingTimeOut = 0; - - BytesToBeReceived = (NumOfBytesToRead > SDMMC_DMA_TRANSFER_SIZE) ? - SDMMC_DMA_TRANSFER_SIZE : NumOfBytesToRead; - - PollingTimeOut = (NumOfBytesToRead > SDMMC_TIMEOUT_CALCULATION_SIZE) ? - (SDMMC_MIN_POLLING_TIME_USEC * (NumOfBytesToRead/ - SDMMC_TIMEOUT_CALCULATION_SIZE)) : SDMMC_MIN_POLLING_TIME_USEC; - if (NumOfBytesToRead > SDMMC_DMA_TRANSFER_SIZE) - { - ConfigureInterrupts(hSdio, 0, SDIO_INTERRUPTS, - (SDIO_ERROR_INTERRUPTS|NvDdkSdioCommandStatus_TransferComplete| - NvDdkSdioCommandStatus_DMA)); - } - else - { - ConfigureInterrupts(hSdio, 0, SDIO_INTERRUPTS, (SDIO_ERROR_INTERRUPTS| - NvDdkSdioCommandStatus_TransferComplete)); - } - /* this turns on the sdio clock */ - Error = SdioBlockTransfer(hSdio, - NumOfBytesToRead, - hSdio->pPhysBuffer, - pRWCommand, - HWAutoCMD12Enable, - NV_TRUE); - if (Error == NvSuccess) - { - // poll for the transfer complete interrupt - while (PollTime < PollingTimeOut) - { - IntrStatus = SDMMC_REGR(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS); - if (IntrStatus & SDMMC_ERROR_STATUS_VALUE) - { - // Disable the error interrupts - ConfigureInterrupts(hSdio, 0, SDIO_ERROR_INTERRUPTS, 0); - - // check if there are any command errors - if (IntrStatus & SDIO_CMD_ERROR_INTERRUPTS) - { - // Rest the cmd line if there are any command related errors - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_CMD_LINE, RESETED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - } - else - { - // reset the dat line if there are any data transfer errors - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_DAT_LINE, RESETED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - } - - // clear the error interrupts - IntrStatus &= SDMMC_ERROR_STATUS_VALUE; - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, IntrStatus); - *SdioStatus = IntrStatus; - - // Do the error recovery - PrivSdioErrorRecovery(hSdio); - Error = NvError_SdioReadFailed; - SD_PRINT(("SDIO_DDK polling read failed error[0x%x] \ - instance[%d]\n", *SdioStatus, hSdio->Instance)); - break; - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, DMA_INTERRUPT, IntrStatus)) - { - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, DMA_INTERRUPT, GEN_INT); - // clearing the DMA interrupt - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, IntrStatus)) - { - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, GEN_INT); - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - IsTransferCompleted = NV_TRUE; - } - else - { - NvOsWaitUS(SDMMC_POLLING_DELAY_USEC); - PollTime += SDMMC_POLLING_DELAY_USEC; - continue; - } - - if (BytesToBeReceived) - { - BytesToBeCopied = BytesToBeReceived; - BytesReceived += BytesToBeReceived; - BytesToBeReceived = NumOfBytesToRead - BytesReceived; - } - if (BytesToBeReceived == 0) - { - if (IsTransferCompleted) - { - NvOsMemcpy(ReadPtr, VirtAddr, BytesToBeCopied); - break; - } - else - { - NvOsWaitUS(SDMMC_POLLING_DELAY_USEC); - PollTime += SDMMC_POLLING_DELAY_USEC; - continue; - } - } - else if (BytesToBeReceived > SDMMC_DMA_TRANSFER_SIZE) - { - BytesToBeReceived = SDMMC_DMA_TRANSFER_SIZE; - } - - if (PhysAddr == hSdio->pPhysBuffer) - { - PhysAddr += SDMMC_DMA_TRANSFER_SIZE; - // program the system start address - SDMMC_REGW(hSdio->pSdioVirtualAddress, SYSTEM_ADDRESS, PhysAddr); - NvOsMemcpy(ReadPtr, VirtAddr, BytesToBeCopied); - VirtAddr += SDMMC_DMA_TRANSFER_SIZE; - } - else - { - PhysAddr = hSdio->pPhysBuffer; - // program the system start address - SDMMC_REGW(hSdio->pSdioVirtualAddress, SYSTEM_ADDRESS, hSdio->pPhysBuffer); - NvOsMemcpy(ReadPtr, VirtAddr, BytesToBeCopied); - VirtAddr = hSdio->pVirtBuffer; - } - ReadPtr += BytesToBeCopied; - NvOsWaitUS(SDMMC_POLLING_DELAY_USEC); - PollTime += SDMMC_POLLING_DELAY_USEC; - } - if (PollTime >= PollingTimeOut) - { - PrivSdioReset(hSdio); - Error = NvError_SdioReadFailed; - SD_PRINT(("SDIO_DDK polling read timeout Instance[%d]\n", - hSdio->Instance)); - } - SdioConfigureCardClock(hSdio, NV_FALSE); - } - return Error; -} - -NvError -NvDdkSdioRead( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfBytesToRead, - void *pReadBuffer, - NvDdkSdioCommand *pRWCommand, - NvBool HWAutoCMD12Enable, - NvU32* SdioStatus) -{ - NvError Error = NvError_SdioReadFailed; - NvDdkSdioStatus* ControllerStatus = NULL; - NvU32 BytesToBeReceived = 0; - NvU32 BytesReceived = 0; - NvU8* ReadPtr = (NvU8*)pReadBuffer; - NvU32 BytesToBeCopied = 0; - NvU8* VirtAddr = (NvU8*)hSdio->pVirtBuffer; - NvU32 PhysAddr = hSdio->pPhysBuffer; - -#if !NV_OAL -#if ENABLE_READ_BUSY_HINTS - // Enable pulse mode - NvRmDfsBusyHint pMultiHintOff[3] = { - {NvRmDfsClockId_Emc, 0, 0, NV_TRUE}, - {NvRmDfsClockId_System, 0, 0, NV_TRUE}, - {NvRmDfsClockId_Cpu, 0, 0, NV_TRUE} }; - - NvRmDfsBusyHint pMultiHintOn[3] = { - {NvRmDfsClockId_Emc, NV_WAIT_INFINITE, 80000, NV_TRUE}, - {NvRmDfsClockId_System, NV_WAIT_INFINITE, 80000, NV_TRUE}, - {NvRmDfsClockId_Cpu, NV_WAIT_INFINITE, 240000, NV_TRUE} }; -#endif -#endif - - NV_ASSERT(hSdio); - NV_ASSERT(pReadBuffer); - NV_ASSERT(pRWCommand); - - *SdioStatus = NvDdkSdioError_None; -#if NV_OAL - Error = PrivSdioPollingRead(hSdio, NumOfBytesToRead, pReadBuffer, - pRWCommand, HWAutoCMD12Enable, SdioStatus); - return Error; -#endif - - // To get better performance, use polling (to eliminate interrupt latency) for lower transfer sizes. - if (NumOfBytesToRead <= SDMMC_MAX_POLLING_SIZE) - { - Error = PrivSdioPollingRead(hSdio, NumOfBytesToRead, pReadBuffer, - pRWCommand, HWAutoCMD12Enable, SdioStatus); - return Error; - } - -#if !NV_OAL -#if ENABLE_READ_BUSY_HINTS - // Enable busy hints - NV_ASSERT_SUCCESS( - NvRmPowerBusyHintMulti(hSdio->hRm, - hSdio->SdioRmPowerClientId, - pMultiHintOn, - 3, - NvRmDfsBusyHintSyncMode_Async)); -#endif -#endif - - ControllerStatus = hSdio->ControllerStatus; - - BytesToBeReceived = (NumOfBytesToRead > SDMMC_DMA_TRANSFER_SIZE) ? - SDMMC_DMA_TRANSFER_SIZE : NumOfBytesToRead; - if (NumOfBytesToRead == SDMMC_DMA_TRANSFER_SIZE) - { - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, (NvDdkSdioCommandStatus_CommandComplete|NvDdkSdioCommandStatus_DMA), 0); - } - else - { - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, NvDdkSdioCommandStatus_CommandComplete, 0); - } - - /* this function turns on the sdio clock */ - Error = SdioBlockTransfer(hSdio, - NumOfBytesToRead, - PhysAddr, - pRWCommand, - HWAutoCMD12Enable, - NV_TRUE); - if (Error == NvSuccess) - { - // loop till we receive all the requested bytes - while (BytesReceived != NumOfBytesToRead) - { - Error = NvOsSemaphoreWaitTimeout(hSdio->PrivSdioSema, NVDDK_SDMMC_DATA_TIMEOUT_MSEC); - if (Error == NvSuccess) - { - if (ControllerStatus->SDErrorStatus != NvDdkSdioError_None) - { -#if !NV_OAL -#if ENABLE_READ_BUSY_HINTS - // Disable busy hints - NV_ASSERT_SUCCESS( - NvRmPowerBusyHintMulti(hSdio->hRm, - hSdio->SdioRmPowerClientId, - pMultiHintOff, - 3, - NvRmDfsBusyHintSyncMode_Async)); -#endif -#endif - *SdioStatus = ControllerStatus->SDErrorStatus; - if (ControllerStatus->SDErrorStatus & NvDdkSdioError_DataCRC) - { - NV_DEBUG_PRINTF(("NvDdkSdio Read Error Status: Data CRC error occured \n")); - PrivSdioErrorRecovery(hSdio); - } - else - { - PrivSdioReset(hSdio); - } - SdioConfigureCardClock(hSdio, NV_FALSE); - return Error; - } - else - { - BytesToBeCopied = BytesToBeReceived; - BytesReceived += BytesToBeReceived; - BytesToBeReceived = NumOfBytesToRead - BytesReceived; - if (BytesToBeReceived == 0) - { - NvOsMemcpy(ReadPtr, VirtAddr, BytesToBeCopied); - break; - } - else if (BytesToBeReceived == SDMMC_DMA_TRANSFER_SIZE) - { - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, (NvDdkSdioCommandStatus_DMA|NvDdkSdioCommandStatus_CommandComplete), 0); - } - else if (BytesToBeReceived > SDMMC_DMA_TRANSFER_SIZE) - { - BytesToBeReceived = SDMMC_DMA_TRANSFER_SIZE; - } - - if (PhysAddr == hSdio->pPhysBuffer) - { - PhysAddr += SDMMC_DMA_TRANSFER_SIZE; - // program the system start address - SDMMC_REGW(hSdio->pSdioVirtualAddress, SYSTEM_ADDRESS, PhysAddr); - NvOsMemcpy(ReadPtr, VirtAddr, BytesToBeCopied); - VirtAddr += SDMMC_DMA_TRANSFER_SIZE; - } - else - { - PhysAddr = hSdio->pPhysBuffer; - // program the system start address - SDMMC_REGW(hSdio->pSdioVirtualAddress, SYSTEM_ADDRESS, hSdio->pPhysBuffer); - NvOsMemcpy(ReadPtr, VirtAddr, BytesToBeCopied); - VirtAddr = hSdio->pVirtBuffer; - } - ReadPtr += BytesToBeCopied; - } - } - else - { -#if !NV_OAL -#if ENABLE_READ_BUSY_HINTS - // Disable busy hints - NV_ASSERT_SUCCESS( - NvRmPowerBusyHintMulti(hSdio->hRm, - hSdio->SdioRmPowerClientId, - pMultiHintOff, - 3, - NvRmDfsBusyHintSyncMode_Async)); -#endif -#endif - // break if there is any timeout - *SdioStatus = ControllerStatus->SDErrorStatus; - // !!! JN: don't leave the clock togging in case of an error. - // probably should do a reset or something here, not sure? - PrivSdioReset(hSdio); - SdioConfigureCardClock(hSdio, NV_FALSE); - SD_PRINT(("SDIO_DDK normal read timeout Instance[%d]\n", - hSdio->Instance)); - return Error; - } - } - } - -#if !NV_OAL -#if ENABLE_READ_BUSY_HINTS - // Disable Multihint - NV_ASSERT_SUCCESS( - NvRmPowerBusyHintMulti(hSdio->hRm, - hSdio->SdioRmPowerClientId, - pMultiHintOff, - 3, - NvRmDfsBusyHintSyncMode_Async)); -#endif -#endif - - SdioConfigureCardClock(hSdio, NV_FALSE); - - *SdioStatus = ControllerStatus->SDErrorStatus; - return Error; -} - -static NvError -PrivSdioPollingWrite( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfBytesToWrite, - void *pWriteBuffer, - NvDdkSdioCommand *pRWCommand, - NvBool HWAutoCMD12Enable, - NvU32* SdioStatus) -{ - NvU32 val = 0; - NvU32 PollTime = 0; - NvU8* VirtAddr = (NvU8*)hSdio->pVirtBuffer; - NvError Error = NvError_SdioWriteFailed; - NvU32 BytesToBeSent = 0; - NvU32 BytesSent = 0; - NvU8* WritePtr = (NvU8*)pWriteBuffer; - NvU32 PhysAddr = hSdio->pPhysBuffer; - NvBool IsTransferCompleted = NV_FALSE; - NvU32 IntrStatus = 0; - NvBool IsDmaStarted = NV_FALSE; - NvU32 PollingTimeOut = 0; - - BytesToBeSent = (NumOfBytesToWrite > SDMMC_DMA_TRANSFER_SIZE) ? - SDMMC_DMA_TRANSFER_SIZE : NumOfBytesToWrite; - - PollingTimeOut = (NumOfBytesToWrite > SDMMC_TIMEOUT_CALCULATION_SIZE) ? - (SDMMC_MIN_POLLING_TIME_USEC * (NumOfBytesToWrite/ - SDMMC_TIMEOUT_CALCULATION_SIZE)) : SDMMC_MIN_POLLING_TIME_USEC; - if (NumOfBytesToWrite > SDMMC_DMA_TRANSFER_SIZE) - { - ConfigureInterrupts(hSdio, 0, SDIO_INTERRUPTS, - (SDIO_ERROR_INTERRUPTS|NvDdkSdioCommandStatus_TransferComplete| - NvDdkSdioCommandStatus_DMA)); - } - else - { - ConfigureInterrupts(hSdio, 0, SDIO_INTERRUPTS, (SDIO_ERROR_INTERRUPTS| - NvDdkSdioCommandStatus_TransferComplete)); - } - - NvOsMemcpy(VirtAddr, pWriteBuffer, BytesToBeSent); - - /* this function enables the sdio clock */ - Error = SdioBlockTransfer(hSdio, - NumOfBytesToWrite, - hSdio->pPhysBuffer, - pRWCommand, - HWAutoCMD12Enable, - NV_FALSE); - if (Error == NvSuccess) - { - IsDmaStarted = NV_TRUE; - // poll for the transfer complete interrupt - while (PollTime < PollingTimeOut) - { - if (IsDmaStarted) - { - WritePtr += BytesToBeSent; - BytesSent += BytesToBeSent; - BytesToBeSent = NumOfBytesToWrite - BytesSent; - - BytesToBeSent = - (BytesToBeSent > SDMMC_DMA_TRANSFER_SIZE) ? SDMMC_DMA_TRANSFER_SIZE : BytesToBeSent; - - if (BytesToBeSent) - { - PhysAddr = - (PhysAddr == hSdio->pPhysBuffer) ? (PhysAddr + SDMMC_DMA_TRANSFER_SIZE) : hSdio->pPhysBuffer; - - VirtAddr = - (VirtAddr == hSdio->pVirtBuffer) ? (VirtAddr + SDMMC_DMA_TRANSFER_SIZE) : hSdio->pVirtBuffer; - - NvOsMemcpy(VirtAddr, WritePtr, BytesToBeSent); - } - IsDmaStarted = NV_FALSE; - } - IntrStatus = SDMMC_REGR(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS); - if (IntrStatus & SDMMC_ERROR_STATUS_VALUE) - { - // Disable the error interrupts - ConfigureInterrupts(hSdio, 0, SDIO_ERROR_INTERRUPTS, 0); - - // check if there are any command errors - if (IntrStatus & SDIO_CMD_ERROR_INTERRUPTS) - { - // Rest the cmd line if there are any command related errors - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_CMD_LINE, RESETED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - } - else - { - // reset the dat line if there are any data transfer errors - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_DAT_LINE, RESETED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - } - - // Clear the error interrupts - IntrStatus &= SDMMC_ERROR_STATUS_VALUE; - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, IntrStatus); - *SdioStatus = IntrStatus; - - // Do the error recovery - PrivSdioErrorRecovery(hSdio); - Error = NvError_SdioWriteFailed; - SD_PRINT(("SDIO_DDK polling write failed error[0x%x] \ - Instance[%d]\n", *SdioStatus, hSdio->Instance)); - break; - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, DMA_INTERRUPT, IntrStatus)) - { - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, DMA_INTERRUPT, GEN_INT); - // clearing the DMA interrupt - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, IntrStatus)) - { - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, GEN_INT); - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - IsTransferCompleted = NV_TRUE; - } - else - { - NvOsWaitUS(SDMMC_POLLING_DELAY_USEC); - PollTime += SDMMC_POLLING_DELAY_USEC; - continue; - } - - if (BytesToBeSent) - { - SDMMC_REGW(hSdio->pSdioVirtualAddress, SYSTEM_ADDRESS, PhysAddr); - IsDmaStarted = NV_TRUE; - } - else if (IsTransferCompleted) - { - break; - } - NvOsWaitUS(SDMMC_POLLING_DELAY_USEC); - PollTime += SDMMC_POLLING_DELAY_USEC; - } - if (PollTime >= PollingTimeOut) - { - PrivSdioReset(hSdio); - Error = NvError_SdioWriteFailed; - SD_PRINT(("SDIO_DDK polling write timeout Instance[%d]\n", - hSdio->Instance)); - } - } - /* turn off the sdio clock */ - SdioConfigureCardClock(hSdio, NV_FALSE); - return Error; -} - -NvError -NvDdkSdioWrite( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfBytesToWrite, - void *pWriteBuffer, - NvDdkSdioCommand *pRWCommand, - NvBool HWAutoCMD12Enable, - NvU32* SdioStatus) -{ - NvError Error = NvError_SdioWriteFailed; - NvDdkSdioStatus* ControllerStatus = NULL; - NvU32 BytesToBeSent = 0; - NvU32 BytesSent = 0; - NvU8* WritePtr = (NvU8*)pWriteBuffer; - NvU8* VirtAddr = (NvU8*)hSdio->pVirtBuffer; - NvU32 PhysAddr = hSdio->pPhysBuffer; - NvBool IsDisableDmaInterrupt = NV_FALSE; - - // Disable pulse mode, since performance is hit if pulse mode is used in Write - NvRmDfsBusyHint pMultiHintOff[3] = { - {NvRmDfsClockId_Emc, 0, 0, NV_FALSE}, - {NvRmDfsClockId_System, 0, 0, NV_FALSE}, - {NvRmDfsClockId_Cpu, 0, 0, NV_FALSE} }; - - NvRmDfsBusyHint pMultiHintOn[3] = { - {NvRmDfsClockId_Emc, NV_WAIT_INFINITE, 80000, NV_FALSE}, - {NvRmDfsClockId_System, NV_WAIT_INFINITE, 80000, NV_FALSE}, - {NvRmDfsClockId_Cpu, NV_WAIT_INFINITE, 450000, NV_FALSE} }; - - NV_ASSERT(hSdio); - NV_ASSERT(pWriteBuffer); - NV_ASSERT(pRWCommand); - - *SdioStatus = NvDdkSdioError_None; -#if NV_OAL - Error = PrivSdioPollingWrite(hSdio, NumOfBytesToWrite, pWriteBuffer, - pRWCommand, HWAutoCMD12Enable, SdioStatus); - return Error; -#endif - - // To get better performance, use polling (to eliminate interrupt latency) for lower transfer sizes. - if (NumOfBytesToWrite <= SDMMC_MAX_POLLING_SIZE) - { - Error = PrivSdioPollingWrite(hSdio, NumOfBytesToWrite, pWriteBuffer, - pRWCommand, HWAutoCMD12Enable, SdioStatus); - return Error; - } - - // Enable busy hints - NV_ASSERT_SUCCESS( - NvRmPowerBusyHintMulti(hSdio->hRm, - hSdio->SdioRmPowerClientId, - pMultiHintOn, - 3, - NvRmDfsBusyHintSyncMode_Async)); - - ControllerStatus = hSdio->ControllerStatus; - BytesToBeSent = (NumOfBytesToWrite > SDMMC_DMA_TRANSFER_SIZE) ? - SDMMC_DMA_TRANSFER_SIZE : NumOfBytesToWrite; - - if (NumOfBytesToWrite == SDMMC_DMA_TRANSFER_SIZE) - { - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, (NvDdkSdioCommandStatus_CommandComplete|NvDdkSdioCommandStatus_DMA), 0); - } - else - { - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, NvDdkSdioCommandStatus_CommandComplete, 0); - } - - NvOsMemcpy(VirtAddr, WritePtr, BytesToBeSent); - - /* this enables the sdio clock */ - Error = SdioBlockTransfer(hSdio, - NumOfBytesToWrite, - PhysAddr, - pRWCommand, - HWAutoCMD12Enable, - NV_FALSE); - if (Error == NvSuccess) - { - // loop till we receive all the requested bytes - while (BytesSent != NumOfBytesToWrite) - { - WritePtr += BytesToBeSent; - BytesSent += BytesToBeSent; - BytesToBeSent = NumOfBytesToWrite - BytesSent; - if (BytesToBeSent == 0) - { - Error = NvOsSemaphoreWaitTimeout(hSdio->PrivSdioSema, - NVDDK_SDMMC_DATA_TIMEOUT_MSEC); - break; - } - else if (BytesToBeSent == SDMMC_DMA_TRANSFER_SIZE) - { - IsDisableDmaInterrupt = NV_TRUE; - } - else if (BytesToBeSent > SDMMC_DMA_TRANSFER_SIZE) - { - BytesToBeSent = SDMMC_DMA_TRANSFER_SIZE; - } - - if (PhysAddr == hSdio->pPhysBuffer) - { - PhysAddr += SDMMC_DMA_TRANSFER_SIZE; - VirtAddr += SDMMC_DMA_TRANSFER_SIZE; - } - else - { - PhysAddr = hSdio->pPhysBuffer; - VirtAddr = hSdio->pVirtBuffer; - } - NvOsMemcpy(VirtAddr, WritePtr, BytesToBeSent); - Error = NvOsSemaphoreWaitTimeout(hSdio->PrivSdioSema, - NVDDK_SDMMC_DATA_TIMEOUT_MSEC); - - // issue abort incase of error - if (ControllerStatus->SDErrorStatus != NvDdkSdioError_None) - { - // Disable busy hints - NV_ASSERT_SUCCESS( - NvRmPowerBusyHintMulti(hSdio->hRm, - hSdio->SdioRmPowerClientId, - pMultiHintOff, - 3, - NvRmDfsBusyHintSyncMode_Async)); - *SdioStatus = ControllerStatus->SDErrorStatus; - if (ControllerStatus->SDErrorStatus & NvDdkSdioError_DataCRC) - { - NV_DEBUG_PRINTF(("NvDdkSdio Write Error Status: Data CRC error occured \n")); - PrivSdioErrorRecovery(hSdio); - } - else - { - PrivSdioReset(hSdio); - } - // !!! JN: don't leave the clock toggling if there is an error - SdioConfigureCardClock(hSdio, NV_FALSE); - SD_PRINT(("SDIO_DDK normal write failed error[0x%x] \ - Instance[%d]\n", *SdioStatus, hSdio->Instance)); - return Error; - } - else - { - if (IsDisableDmaInterrupt) - { - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, (NvDdkSdioCommandStatus_DMA|NvDdkSdioCommandStatus_CommandComplete), 0); - } - SDMMC_REGW(hSdio->pSdioVirtualAddress, SYSTEM_ADDRESS, PhysAddr); - } - } - } - - // Disable busy hints - NV_ASSERT_SUCCESS( - NvRmPowerBusyHintMulti(hSdio->hRm, - hSdio->SdioRmPowerClientId, - pMultiHintOff, - 3, - NvRmDfsBusyHintSyncMode_Async)); - SdioConfigureCardClock(hSdio, NV_FALSE); - *SdioStatus = ControllerStatus->SDErrorStatus; - return Error; -} - -void PrivSdioErrorRecovery(NvDdkSdioDeviceHandle hSdio) -{ - - NvU32 val = 0; - - // Issue soft reset - PrivSdioReset(hSdio); - - // For read commands disable AutoCMD12 - if (hSdio->IsRead && (!hSdio->IsSdControllerVersion2)) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, CMD_XFER_MODE); - val = NV_FLD_SET_DRF_DEF(SDMMC, CMD_XFER_MODE, AUTO_CMD12_EN, DISABLE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, CMD_XFER_MODE, val); - } - - // Issue abort - PrivSdioAbort(hSdio); - - if (!hSdio->IsSdControllerVersion2) - { - NvOsWaitUS(NVDDK_SDMMC_DELAY_AFTER_ABORT_USEC); - - // Issue soft reset - PrivSdioReset(hSdio); - } - -} - -NvError -SdioGetPhysAdd( - NvRmDeviceHandle hRmDevice, - NvRmMemHandle* hRmMemHandle, - void** pVirtBuffer, - NvU32 size, - NvU32* pPhysBuffer) -{ - NvU32 SDMMC_ALIGNMENT_SIZE = SDMMC_DMA_TRANSFER_SIZE; - NvError Error = NvError_InvalidAddress; - - // Initialise the handle to NULL - *pPhysBuffer = 0; - *hRmMemHandle = NULL; - - // Create the Memory Handle - Error = NvRmMemHandleCreate(hRmDevice, hRmMemHandle, size); - if (Error != NvSuccess) - { - return Error; - } - - // Allocate the memory - Error = NvRmMemAlloc(*hRmMemHandle, NULL, 0, - SDMMC_ALIGNMENT_SIZE, NvOsMemAttribute_Uncached); - if (Error != NvSuccess) - { - NvRmMemHandleFree(*hRmMemHandle); - return Error; - } - - // Pin the memory and Get Physical Address - *pPhysBuffer = NvRmMemPin(*hRmMemHandle); - - Error = NvRmMemMap(*hRmMemHandle, 0, size, NVOS_MEM_READ_WRITE, pVirtBuffer); - if (Error != NvSuccess) - { - NvRmMemUnpin(*hRmMemHandle); - NvRmMemHandleFree(*hRmMemHandle); - return Error; - } - - return NvSuccess; -} - -NvError -SdioBlockTransfer( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfRWBytes, - NvU32 pReadBuffer, - NvDdkSdioCommand *pRWRequest, - NvBool HWAutoCMD12Enable, - NvBool IsRead) -{ - NvBool IsCrcCheckEnable = NV_FALSE; - NvBool IsIndexCheckEnable = NV_FALSE; - NvU32 IsControllerBusy = 0; - NvBool IsDataCommand = NV_TRUE; - NvU32 NumOfBlocks = 0; - NvU32 CmdXferReg = 0; - NvU32 BlkSizeCountReg = 0; - NvU32 SdioBlockSize = 512; - NvDdkSdioStatus* ControllerStatus = NULL; - - if (pRWRequest->BlockSize > hSdio->MaxBlockLength) - { - return NvError_SdioBadBlockSize; - } - - ControllerStatus = hSdio->ControllerStatus; - // clear the previous status if any - ControllerStatus->SDControllerStatus = NvDdkSdioCommandStatus_None; - ControllerStatus->SDErrorStatus = NvDdkSdioError_None; - hSdio->RequestType = NVDDK_SDIO_NORMAL_REQUEST; - - hSdio->IsRead = IsRead; - SdioBlockSize = pRWRequest->BlockSize; - NumOfBlocks = NumOfRWBytes/SdioBlockSize; - - if (NumOfBlocks > SDMMC_MAX_NUMBER_OF_BLOCKS) - return NvError_InvalidSize; - // set DMA (system) address - SDMMC_REGW(hSdio->pSdioVirtualAddress, SYSTEM_ADDRESS, pReadBuffer); - - if (NumOfBlocks > 1) - { - // Enable multi block in Cmd xfer register - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, MULTI_BLOCK_SELECT, ENABLE); - - // Enable Block Count (used in case of multi-block transfers) - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, BLOCK_COUNT_EN, ENABLE); - - // set Auto CMD12 (stop transmission) - CmdXferReg |= - NV_DRF_NUM(SDMMC, CMD_XFER_MODE, AUTO_CMD12_EN, HWAutoCMD12Enable); - } - - if ((SdioBlockSize >= 1) && (SdioBlockSize < 4096)) - { - BlkSizeCountReg |= - NV_DRF_NUM(SDMMC, BLOCK_SIZE_BLOCK_COUNT, XFER_BLOCK_SIZE_12, - NV_FALSE); - } - else - { - NV_ASSERT(SdioBlockSize && (SdioBlockSize < 8192)); - // Transfer Block Size 12th bit. This bit is added to support 4Kb Data block transfer - BlkSizeCountReg |= - NV_DRF_NUM(SDMMC, BLOCK_SIZE_BLOCK_COUNT, XFER_BLOCK_SIZE_12, - NV_TRUE); - } - - BlkSizeCountReg |= NV_DRF_NUM(SDMMC, BLOCK_SIZE_BLOCK_COUNT, XFER_BLOCK_SIZE_11_0, - SdioBlockSize); - - // set number of blocks to be read/written (block count) - BlkSizeCountReg |= - NV_DRF_NUM(SDMMC, BLOCK_SIZE_BLOCK_COUNT, BLOCKS_COUNT, NumOfBlocks); - - BlkSizeCountReg |= NV_DRF_NUM(SDMMC, BLOCK_SIZE_BLOCK_COUNT, - HOST_DMA_BUFFER_SIZE, SDMMC_DMA_BUFFER_SIZE); - - SDMMC_REGW(hSdio->pSdioVirtualAddress, BLOCK_SIZE_BLOCK_COUNT, BlkSizeCountReg); - - // set the command number - CmdXferReg |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, COMMAND_INDEX, - pRWRequest->CommandCode); - - // set the data command bit - CmdXferReg |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, DATA_PRESENT_SELECT, - IsDataCommand); - - // set the transfer direction - CmdXferReg |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, DATA_XFER_DIR_SEL, IsRead); - - // enable DMA - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, DMA_EN, ENABLE); - - // set the cmd type - CmdXferReg |= - NV_DRF_NUM(SDMMC, CMD_XFER_MODE, COMMAND_TYPE, pRWRequest->CommandType); - - /* set the response type */ - switch (pRWRequest->ResponseType) - { - case NvDdkSdioRespType_NoResp: - IsCrcCheckEnable = NV_FALSE; - IsIndexCheckEnable = NV_FALSE; - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - NO_RESPONSE); - break; - - case NvDdkSdioRespType_R1: - case NvDdkSdioRespType_R5: - case NvDdkSdioRespType_R6: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_TRUE; - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48); - break; - - case NvDdkSdioRespType_R2: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_FALSE; - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_136); - break; - - case NvDdkSdioRespType_R3: - case NvDdkSdioRespType_R4: - IsCrcCheckEnable = NV_FALSE; - IsIndexCheckEnable = NV_FALSE; - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48); - break; - - case NvDdkSdioRespType_R1b: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_TRUE; - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48BUSY); - break; - - case NvDdkSdioRespType_R7: - IsCrcCheckEnable = NV_TRUE; - IsIndexCheckEnable = NV_FALSE; - CmdXferReg |= NV_DRF_DEF(SDMMC, CMD_XFER_MODE, RESP_TYPE_SELECT, - RESP_LENGTH_48); - break; - - default: - NV_ASSERT(0); - } - - // set the is indexed - CmdXferReg |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, CMD_INDEX_CHECK_EN, - IsIndexCheckEnable); - - // set the is crc - CmdXferReg |= NV_DRF_NUM(SDMMC, CMD_XFER_MODE, CMD_CRC_CHECK_EN, - IsCrcCheckEnable); - - IsControllerBusy = SdioIsControllerBusy(hSdio, IsDataCommand); - if (IsControllerBusy) - { - NV_DEBUG_PRINTF(("controller is busy\n")); - return NvError_SdioControllerBusy; - } - - ControllerStatus->SDControllerStatus = NvDdkSdioCommandStatus_None; - ControllerStatus->SDErrorStatus = NvDdkSdioError_None; - - /* now write to the command argument register */ - SDMMC_REGW(hSdio->pSdioVirtualAddress, ARGUMENT, pRWRequest->CmdArgument); - - SdioConfigureCardClock(hSdio, NV_TRUE); - - /* now write to the command xfer register */ - SDMMC_REGW(hSdio->pSdioVirtualAddress, CMD_XFER_MODE, CmdXferReg); - - return NvSuccess; -} - -void -PrivSdioGetCaps( - NvRmDeviceHandle hDevice, - NvDdkSdioHostCapabilities *pHostCap, - NvU32 instance) -{ - static NvDdkSdioHostCapabilities s_SdioCap[2]; - static NvDdkSdioHostCapabilities* s_pSdioCap = NULL; - - static NvRmModuleCapability s_SdioCaps[] = - { - {1, 0, 0, &s_SdioCap[0]}, - {2, 0, 0, &s_SdioCap[1]}, - }; - NV_ASSERT(hDevice); - NV_ASSERT(pHostCap); - - s_SdioCap[0].MaxInstances = NvRmModuleGetNumInstances(hDevice, NvRmModuleID_Sdio); - s_SdioCap[0].IsAutoCMD12Supported = NV_TRUE; - s_SdioCap[0].IsSdControllerVersion2 = NV_FALSE; - s_SdioCap[1].MaxInstances = NvRmModuleGetNumInstances(hDevice, NvRmModuleID_Sdio); - s_SdioCap[1].IsAutoCMD12Supported = NV_TRUE; - s_SdioCap[1].IsSdControllerVersion2 = NV_TRUE; - - NV_ASSERT_SUCCESS(NvRmModuleGetCapabilities(hDevice, - NVRM_MODULE_ID(NvRmModuleID_Sdio, instance), - s_SdioCaps, NV_ARRAY_SIZE(s_SdioCaps), (void**)&s_pSdioCap)); - - // Fill the client capabilities structure. - NvOsMemcpy(pHostCap, s_pSdioCap, sizeof(NvDdkSdioHostCapabilities)); -} - -NvError -NvDdkSdioGetCapabilities( - NvRmDeviceHandle hDevice, - NvDdkSdioHostCapabilities *pHostCap, - NvDdkSdioInterfaceCapabilities *pInterfaceCap, - NvU32 instance) -{ - NvRmModuleSdmmcInterfaceCaps SdioCaps; - NvError Error = NvSuccess; - const NvOdmQuerySdioInterfaceProperty* pSdioInterfaceCaps = NULL; - - PrivSdioGetCaps(hDevice, pHostCap, instance); - - Error = NvRmGetModuleInterfaceCapabilities( - hDevice, - NVRM_MODULE_ID(NvRmModuleID_Sdio, instance), - sizeof(NvRmModuleSdmmcInterfaceCaps), - &SdioCaps); - - if (Error != NvSuccess) - return Error; - - pInterfaceCap->SDIOCardSettlingDelayMSec = 0; - pSdioInterfaceCaps = NvOdmQueryGetSdioInterfaceProperty(instance); - if (pSdioInterfaceCaps) - { - pInterfaceCap->SDIOCardSettlingDelayMSec = pSdioInterfaceCaps->SDIOCardSettlingDelayMSec; - pInterfaceCap->MmcInterfaceWidth = SdioCaps.MmcInterfaceWidth; - pHostCap->AlwaysON = pSdioInterfaceCaps->AlwaysON; - } - - return NvSuccess; -} - -NvError -NvDdkSdioSetHostBusWidth( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioDataWidth CardDataWidth) -{ - NvU32 DataWidthReg = 0; - NvRmModuleSdmmcInterfaceCaps SdioCaps; - - NV_ASSERT(hSdio); - - // set the buswidth - if (CardDataWidth != NvDdkSdioDataWidth_8Bit) - { - DataWidthReg = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - DataWidthReg = NV_FLD_SET_DRF_NUM(SDMMC, POWER_CONTROL_HOST, DATA_XFER_WIDTH, - CardDataWidth, DataWidthReg); - DataWidthReg = NV_FLD_SET_DRF_DEF(SDMMC, POWER_CONTROL_HOST, - EXTENDED_DATA_TRANSFER_WIDTH, NOBIT_8, DataWidthReg); - } - else - { - NV_ASSERT_SUCCESS(NvRmGetModuleInterfaceCapabilities( - hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - sizeof(NvRmModuleSdmmcInterfaceCaps), - &SdioCaps)); - // check if 8bit mode is supported - if (SdioCaps.MmcInterfaceWidth != 8) - { - return NvError_NotSupported; - } - - DataWidthReg = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - DataWidthReg = NV_FLD_SET_DRF_NUM(SDMMC, POWER_CONTROL_HOST, DATA_XFER_WIDTH, - 0, DataWidthReg); - DataWidthReg = NV_FLD_SET_DRF_DEF(SDMMC, POWER_CONTROL_HOST, - EXTENDED_DATA_TRANSFER_WIDTH, BIT_8, DataWidthReg); - } - - - // now write to the power control host register - SDMMC_REGW(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST, DataWidthReg); - - hSdio->BusWidth = CardDataWidth; - - return NvSuccess; -} - -NvError NvDdkSdioHighSpeedEnable(NvDdkSdioDeviceHandle hSdio) -{ - NvU32 val = 0; - - NV_ASSERT(hSdio); - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, CAPABILITIES); - val = NV_DRF_VAL(SDMMC, CAPABILITIES, HIGH_SPEED_SUPPORT, val); - if (val) - { - // set the high speed enable - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - val = NV_FLD_SET_DRF_DEF(SDMMC, POWER_CONTROL_HOST, HIGH_SPEED_EN, - HIGH_SPEED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST, val); - } - - return NvSuccess; -} - -NvError NvDdkSdioHighSpeedDisable(NvDdkSdioDeviceHandle hSdio) -{ - NvU32 val = 0; - - NV_ASSERT(hSdio); - - // disable high speed mode - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - val = NV_FLD_SET_DRF_DEF(SDMMC, POWER_CONTROL_HOST, HIGH_SPEED_EN, - NORMAL_SPEED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST, val); - - return NvSuccess; -} - -void NvDdkSdioResetController(NvDdkSdioDeviceHandle hSdio) -{ - NvU32 val = 0; - - NV_ASSERT(hSdio); - - // reset the controller write (1) to the reset_all field. - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_ALL, RESETED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); -} - -void NvDdkSdioClose(NvDdkSdioDeviceHandle hSdio) -{ - if (NULL != hSdio) - { - NV_ASSERT_SUCCESS(NvRmSetModuleTristate(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), NV_TRUE)); - - /* disable power */ - NV_ASSERT_SUCCESS(NvRmPowerVoltageControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NvRmVoltsOff, - NvRmVoltsOff, - NULL, - 0, - NULL)); -#if !NV_OAL - NvRmMemUnmap(hSdio->hRmMemHandle, hSdio->pVirtBuffer, SDMMC_MEMORY_BUFFER_SIZE); -#endif - NvRmMemUnpin(hSdio->hRmMemHandle); - NvRmMemHandleFree(hSdio->hRmMemHandle); - - // disable clock to sdio controller - NvRmPowerModuleClockControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NV_FALSE); - - // unregister with the power manager - NvRmPowerUnRegister(hSdio->hRm, hSdio->SdioRmPowerClientId); - - // unregister/disable interrupt handler - NvRmInterruptUnregister(hSdio->hRm, hSdio->InterruptHandle); - hSdio->InterruptHandle = NULL; - -#if !NV_OAL - // unregister the gpio interrupt handler - NvRmGpioInterruptUnregister(hSdio->hGpio, hSdio->hRm, hSdio->GpioIntrHandle); -#endif - // destory the internal sdio abort semaphore - NvOsSemaphoreDestroy(hSdio->PrivSdioSema); - hSdio->PrivSdioSema = NULL; - - // Unmap the sdio register virtual address space - NvRmPhysicalMemUnmap(hSdio->pSdioVirtualAddress, - hSdio->SdioBankSize); -#if !NV_OAL - NvRmGpioConfigPins(hSdio->hGpio, &hSdio->CardDetectPin, 1, - NvRmGpioPinMode_Inactive); -#endif - if (hSdio->SdioOdmHandle) - { - NvOdmSdioClose(hSdio->SdioOdmHandle); - } - NvOsIntrMutexDestroy(hSdio->SdioThreadSafetyMutex); - hSdio->SdioThreadSafetyMutex = NULL; - NvOsFree(hSdio->ControllerStatus); - hSdio->ControllerStatus = NULL; - NvOsSemaphoreDestroy(hSdio->SdioPowerMgtSema); - hSdio->SdioPowerMgtSema = NULL; - NvOsFree(hSdio); - hSdio = NULL; - } -} - -NvError -NvDdkSdioIsCardInserted( - NvDdkSdioDeviceHandle hSdio, - NvBool *IscardInserted) -{ -#if NV_OAL - *IscardInserted = NV_TRUE; - return NvError_SdioCardAlwaysPresent; -#else - NvRmGpioPinState val = NvRmGpioPinState_Low; - NvU32 PinCount = 0; - const NvOdmGpioPinInfo *GpioPinInfo; - const NvOdmQuerySdioInterfaceProperty* hOdmSdioInterface = NULL; - - GpioPinInfo = NvOdmQueryGpioPinMap(NvOdmGpioPinGroup_Sdio, hSdio->Instance, &PinCount); - if (GpioPinInfo) - { - NvRmGpioReadPins(hSdio->hGpio, &(hSdio->CardDetectPin), &val, 1); - if (val == GpioPinInfo[0].activeState) - *IscardInserted = NV_TRUE; - else - *IscardInserted = NV_FALSE; - return NvSuccess; - } - else - { - *IscardInserted = NV_FALSE; - hOdmSdioInterface = NvOdmQueryGetSdioInterfaceProperty(hSdio->Instance); - if (hOdmSdioInterface) - { - if (!hOdmSdioInterface->IsCardRemovable) - { - *IscardInserted = NV_TRUE; - return NvError_SdioCardAlwaysPresent; - } - } - return NvError_SdioAutoDetectCard; - } -#endif -} - -NvError -NvDdkSdioIsWriteProtected( - NvDdkSdioDeviceHandle hSdio, - NvRmGpioHandle hGpio, - NvBool *IsWriteprotected) -{ -#if !NV_OAL - NvRmGpioPinState val = NvRmGpioPinState_Low; - NvU32 PinCount = 0; - const NvOdmGpioPinInfo *GpioPinInfo; - NvBool IsCardInserted = NV_FALSE; - - NV_ASSERT(hGpio); - NV_ASSERT(IsWriteprotected); - - GpioPinInfo = NvOdmQueryGpioPinMap(NvOdmGpioPinGroup_Sdio, hSdio->Instance, &PinCount); - if (GpioPinInfo) - { - // Check whether the write protect gpio pin is supported or not - if (PinCount >= 2) - { - if (NvDdkSdioIsCardInserted(hSdio, &IsCardInserted)) - { - return NvError_SdioCardNotPresent; - } - NvRmGpioReadPins(hGpio, &(hSdio->WriteProtectPin), &val, 1); - if (val == GpioPinInfo[1].activeState) - *IsWriteprotected = NV_TRUE; - else - *IsWriteprotected = NV_FALSE; - return NvSuccess; - } - } -#endif - return NvError_NotSupported; -} - -NvError -SdioRegisterInterrupts( - NvRmDeviceHandle hRm, - NvDdkSdioDeviceHandle hSdio) -{ - NvU32 IrqList; - NvOsInterruptHandler IntHandlers; - if (hSdio->InterruptHandle) - { - return NvSuccess; - } - IrqList = NvRmGetIrqForLogicalInterrupt( - hRm, NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), 0); - IntHandlers = SdioIsr; - return NvRmInterruptRegister(hRm, 1, &IrqList, &IntHandlers, hSdio, - &hSdio->InterruptHandle, NV_TRUE); -} - -static void SdioIsr(void* args) -{ - NvDdkSdioDeviceHandle hSdio; - volatile NvU32 InterruptStatus = 0; - volatile NvU32 val = 0; - NvDdkSdioStatus* ControllerStatus = NULL; - NvBool IsClkStable = NV_FALSE; - - hSdio = args; - - if (hSdio->ISControllerSuspended && hSdio->IsSdControllerVersion2) - { - // enable clock to sdio controller - NvRmPowerModuleClockControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NV_TRUE); - - // enable internal clock to sdio - IsClkStable = SdioEnableInternalClock(hSdio); - if (!IsClkStable) - { - NV_ASSERT(!"Sdio controller internal clock not stable"); - SD_PRINT(("Sdio controller internal clock not stable\n")); - } - - // Enable SDMMC_CLK bit in VENDOR_CLOCK_CONTROL register - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, VENDOR_CLOCK_CNTRL); - val = NV_FLD_SET_DRF_DEF(SDMMC, VENDOR_CLOCK_CNTRL, - SDMMC_CLK, ENABLE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, VENDOR_CLOCK_CNTRL, val); - } - - // update the Controller status - InterruptStatus = SDMMC_REGR(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS); - - ControllerStatus = hSdio->ControllerStatus; - if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, CARD_INTERRUPT, InterruptStatus)) - { - if (hSdio->IsAcceptCardEvents == NV_TRUE) - { - // Disable the card interrupt - NvDdkSdioEnableIoMode(hSdio, NV_FALSE); - ControllerStatus->SDControllerStatus |= NvDdkSdioCommandStatus_Card; - NvOsSemaphoreSignal(hSdio->NotificationSema); - } - else - { - // Disable the card interrupt - NvDdkSdioEnableIoMode(hSdio, NV_FALSE); - ControllerStatus->SDControllerStatus |= NvDdkSdioCommandStatus_Card; - } - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, BLOCK_GAP_EVENT, InterruptStatus)) - { - // read transaction - if (hSdio->IsRead == NV_TRUE) - { - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, GEN_INT); - val |= NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, BLOCK_GAP_EVENT, GEN_INT); - - // Disable card clock - SdioConfigureCardClock(hSdio, NV_FALSE); - NvOsWaitUS(SDMMC_ABORT_DELAY_USEC); - // Clearblock gap event and error interrupts if any - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, - ((InterruptStatus & SDMMC_ERROR_STATUS_VALUE) | val)); - } - // write transaction - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, InterruptStatus)) - { - // transfer complete interrupt - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, GEN_INT); - val |= NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, BLOCK_GAP_EVENT, GEN_INT); - - // Disable card clock - SdioConfigureCardClock(hSdio, NV_FALSE); - // Clear interrupts - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - } - NvOsSemaphoreSignal(hSdio->PrivSdioSema); - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, ERR_INTERRUPT, InterruptStatus)) - { - // Disable the error interrupts - ConfigureInterrupts(hSdio, 0, SDIO_ERROR_INTERRUPTS, 0); - ControllerStatus->SDErrorStatus = InterruptStatus & SDIO_ERROR_INTERRUPTS; - - if (ControllerStatus->SDErrorStatus & (NvDdkSdioError_CommandTimeout | - NvDdkSdioError_CommandCRC | - NvDdkSdioError_CommandEndBit | - NvDdkSdioError_CommandIndex)) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_CMD_LINE, RESETED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - } - if (ControllerStatus->SDErrorStatus & (NvDdkSdioError_DataTimeout | - NvDdkSdioError_DataCRC | - NvDdkSdioError_DataEndBit)) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_DAT_LINE, RESETED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - } - - // Clear the error interrupt - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, - (InterruptStatus & SDMMC_ERROR_STATUS_VALUE)); - NvOsSemaphoreSignal(hSdio->PrivSdioSema); - } - else - { - val = 0; - if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, CMD_COMPLETE, InterruptStatus)) - { - SdioConfigureCardClock(hSdio, NV_FALSE); - // command complete interrupt - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, CMD_COMPLETE, GEN_INT); - ControllerStatus->SDControllerStatus |= - NvDdkSdioCommandStatus_CommandComplete; - - // Clear the source of the interrupt - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - NvOsSemaphoreSignal(hSdio->PrivSdioSema); - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, DMA_INTERRUPT, InterruptStatus)) - { - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, DMA_INTERRUPT, GEN_INT); - ControllerStatus->SDControllerStatus |= NvDdkSdioCommandStatus_DMA; - // clearing the DMA interrupt - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - NvOsSemaphoreSignal(hSdio->PrivSdioSema); - } - else if (NV_DRF_VAL(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, InterruptStatus)) - { - SdioConfigureCardClock(hSdio, NV_FALSE); - // transfer complete interrupt - val = NV_DRF_DEF(SDMMC, INTERRUPT_STATUS, XFER_COMPLETE, GEN_INT); - ControllerStatus->SDControllerStatus |= - NvDdkSdioCommandStatus_TransferComplete; - // Clear the source of the interrupt - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS, val); - NvOsSemaphoreSignal(hSdio->PrivSdioSema); - } - else - { - SD_PRINT(("Interrupt Status 0x%x Instance[%d]\n", - InterruptStatus, hSdio->Instance)); - //NV_ASSERT(!"SDIO_DDK Invalid Interrupt"); - } - } - - NvRmInterruptDone(hSdio->InterruptHandle); -} - -NvError -NvDdkSdioSetSDBusVoltage( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioSDBusVoltage Voltage) -{ - NvU32 val = 0; - - NV_ASSERT(hSdio); - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - val |= NV_DRF_NUM(SDMMC, POWER_CONTROL_HOST, SD_BUS_VOLTAGE_SELECT, Voltage); - SDMMC_REGW(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST, val); - hSdio->BusVoltage = Voltage; - return NvSuccess; -} - -static NvError -SdioSetSlotClockRate( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioClkDivider Divider) -{ - NvU32 val = 0; - - // disable clk - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SD_CLOCK_EN, DISABLE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_NUM(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SDCLK_FREQUENCYSELECT, Divider, val); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SD_CLOCK_EN, ENABLE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - - return NvSuccess; -} - -NvError -NvDdkSdioSetClockFrequency( - NvDdkSdioDeviceHandle hSdio, - NvRmFreqKHz FrequencyKHz, - NvRmFreqKHz* pConfiguredFrequencyKHz) -{ - NvError Error = NvSuccess; - NvRmFreqKHz PrefFreqList[1]; - NvRmFreqKHz CurrentFreq; - NvRmFreqKHz NewFreq; - NvU32 i, Divider = 0; - NvU32 Difference = 0xFFFFFFFF; - NV_ASSERT(hSdio); - - PrefFreqList[0] = FrequencyKHz; - - // first disable the clk - Error = NvRmPowerModuleClockControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NV_FALSE); - if (Error) - { - return Error; - } - - // now enable clock to sdio controller - Error = NvRmPowerModuleClockControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NV_TRUE); - if (Error) - { - return Error; - } - - // request for clk - Error = NvRmPowerModuleClockConfig(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - SdioNormalModeMinFreq, - ((PrefFreqList[0] < SdioNormalModeMaxFreq) ? SdioNormalModeMaxFreq : - SdioHighSpeedModeMaxFreq), - PrefFreqList, - 1, - &CurrentFreq, NvRmClockConfig_QuietOverClock); - if (Error) - { - return Error; - } - - if (PrefFreqList[0] < CurrentFreq) - { - for (i = 0; i < 9; i++) - { - NewFreq = (CurrentFreq >> i); - if ((DIFF_FREQ(PrefFreqList[0], NewFreq)) < Difference) - { - Difference = DIFF_FREQ(PrefFreqList[0], NewFreq); - Divider = i; - } - } - } - - if (pConfiguredFrequencyKHz != NULL) - { - *pConfiguredFrequencyKHz = (CurrentFreq >> Divider); - } - - // set the clk divider to zero - if (Divider == 0) - { - Error = SdioSetSlotClockRate(hSdio, NvDdkSdioClkDivider_DIV_BASE); - } - else - { - Error = SdioSetSlotClockRate(hSdio, (NvDdkSdioClkDivider)(1 <<(Divider - 1))); - } - - hSdio->ConfiguredFrequency = CurrentFreq; - return Error; -} - -NvError NvDdkSdioSetBlocksize(NvDdkSdioDeviceHandle hSdio, NvU32 Blocksize) -{ - NvU32 val = 0; - - NV_ASSERT(hSdio); - - if (Blocksize > hSdio->MaxBlockLength) - { - return NvError_SdioBadBlockSize; - } - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, BLOCK_SIZE_BLOCK_COUNT); - if ((Blocksize >= 1) && (Blocksize < 4096)) - { - val = - NV_FLD_SET_DRF_NUM(SDMMC, BLOCK_SIZE_BLOCK_COUNT, XFER_BLOCK_SIZE_12, - NV_FALSE, val); - } - else - { - NV_ASSERT(Blocksize && (Blocksize < 8192)); - // Transfer Block Size 12th bit. This bit is added to support 4Kb Data block transfer - val = - NV_FLD_SET_DRF_NUM(SDMMC, BLOCK_SIZE_BLOCK_COUNT, XFER_BLOCK_SIZE_12, - NV_TRUE, val); - } - val = NV_FLD_SET_DRF_NUM(SDMMC, BLOCK_SIZE_BLOCK_COUNT, XFER_BLOCK_SIZE_11_0, - Blocksize, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, BLOCK_SIZE_BLOCK_COUNT, val); - - // read back the block size - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, BLOCK_SIZE_BLOCK_COUNT); - val = NV_DRF_VAL(SDMMC, BLOCK_SIZE_BLOCK_COUNT, XFER_BLOCK_SIZE_11_0, val); - if (val != Blocksize) - { - return NvError_SdioBadBlockSize; - } - - return NvSuccess; -} - -NvBool SdioIsReset(NvDdkSdioDeviceHandle hSdio) -{ - NvU32 val = 0; - NvU32 Timeout = 0; - - while ((!val) && (Timeout != SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_USEC)) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_DRF_VAL(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_ALL, val); - NvOsWaitUS(SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_STEP_USEC); - Timeout += SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_STEP_USEC; - } - - return (!val); -} - -NvBool SdioEnableInternalClock(NvDdkSdioDeviceHandle hSdio) -{ - NvU32 val = 0; - NvU32 Timeout = 0; - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - INTERNAL_CLOCK_EN, OSCILLATE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - - while (Timeout != SDMMC_INTERNAL_CLOCK_TIMEOUT_USEC) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_DRF_VAL(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - INTERNAL_CLOCK_STABLE, val); - if (val) - { - break; - } - NvOsWaitUS(SDMMC_INTERNAL_CLOCK_TIMEOUT_STEP_USEC); - Timeout += SDMMC_INTERNAL_CLOCK_TIMEOUT_STEP_USEC; - } - - return (val); -} - -NvError SdioEnableCardClock(NvDdkSdioDeviceHandle hSdio, NvBool IsEnable) -{ - NvU32 val = 0; - NvU32 Timeout = 0; - NvU32 IsControllerBusy = 0; - - NV_ASSERT(hSdio); - - NvOsIntrMutexLock(hSdio->SdioThreadSafetyMutex); - if (IsEnable) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SD_CLOCK_EN, ENABLE, val); - if (!hSdio->IsSdControllerVersion2) - { - NvOsWaitUS(10); - } - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - - while (Timeout != SDMMC_INTERNAL_CLOCK_TIMEOUT_USEC) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_DRF_VAL(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - INTERNAL_CLOCK_STABLE, val); - if (val) - { - break; - } - NvOsWaitUS(SDMMC_INTERNAL_CLOCK_TIMEOUT_STEP_USEC); - Timeout += SDMMC_INTERNAL_CLOCK_TIMEOUT_STEP_USEC; - } - } - else - { - // check if controller is bsuy - IsControllerBusy = SdioIsControllerBusy(hSdio, NV_TRUE); - if (IsControllerBusy) - { - NvOsIntrMutexUnlock(hSdio->SdioThreadSafetyMutex); - return NvError_SdioControllerBusy; - } - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, SD_CLOCK_EN, - DISABLE, val); - if (!hSdio->IsSdControllerVersion2) - { - NvOsWaitUS(10); - } - SDMMC_REGW(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - } - NvOsIntrMutexUnlock(hSdio->SdioThreadSafetyMutex); - return NvSuccess; -} - -NvError SdioConfigureCardClock(NvDdkSdioDeviceHandle hSdio, NvBool IsEnable) -{ - NV_ASSERT(hSdio); - - if (!hSdio->IsSdControllerVersion2) - { - SdioEnableCardClock(hSdio, IsEnable); - } - return NvSuccess; -} - -NvError SdioEnableBusPower(NvDdkSdioDeviceHandle hSdio) -{ - NvU32 val = 0; - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - val = NV_FLD_SET_DRF_DEF(SDMMC, POWER_CONTROL_HOST, SD_BUS_POWER, POWER_ON, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST, val); - - return NvSuccess; -} - -NvError - SdioSetDataTimeout( - NvDdkSdioDeviceHandle hSdio, - SdioDataTimeout SdioDataToCounter) -{ - NvU32 val = 0; - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val |= NV_DRF_NUM(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - DATA_TIMEOUT_COUNTER_VALUE, SdioDataToCounter); - SDMMC_REGW(hSdio->pSdioVirtualAddress, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - - return NvSuccess; -} - -static NvU32 -SdioIsControllerBusy( - NvDdkSdioDeviceHandle hSdio, - NvBool IsDataCommand) -{ - volatile NvU32 val = 0; - NvU32 IsControllerBusy = 0; - NvU32 timeout = 0; - - - while (timeout <= SW_CONTROLLER_BUSY_TIMEOUT_USEC) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, PRESENT_STATE); - - // check if CMD line is busy - IsControllerBusy = NV_DRF_VAL(SDMMC, PRESENT_STATE, CMD_INHIBIT_CMD, val); - if (!IsControllerBusy) - { - if (IsDataCommand) - { - // check if DAT line is busy - IsControllerBusy = (NV_DRF_VAL(SDMMC, PRESENT_STATE, CMD_INHIBIT_DAT, val)); - if (!IsControllerBusy) - { - // check if DAT line is busy - IsControllerBusy = NV_DRF_VAL(SDMMC, PRESENT_STATE, DAT_LINE_ACTIVE, val); - if (!IsControllerBusy) - { - break; - } - } - } - else - { - break; - } - } - - NvOsWaitUS(SW_CONTROLLER_BUSY_TIMEOUT_STEP_USEC); - timeout += SW_CONTROLLER_BUSY_TIMEOUT_STEP_USEC; - } - return IsControllerBusy; -} - -void - NvDdkSdioAbort( - NvDdkSdioDeviceHandle hSdio, - SdioRequestType RequestType, - NvU32 FunctionNumber) -{ - NvU32 val; - - hSdio->RequestType = RequestType; - - // enable the stop at block gap - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - val = NV_FLD_SET_DRF_DEF(SDMMC, POWER_CONTROL_HOST, - STOP_AT_BLOCK_GAP_REQUEST, TRANSFER, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST, val); -} - -static void PrivSdioAbort(NvDdkSdioDeviceHandle hSdio) -{ - NvDdkSdioCommand pCommand; - NvError Error = NvSuccess; - NvU32 status = 0; - - // Issue CMD12 - - // For memory cards send command 12 for abort and for i/o cards send command 52 for abort - if (hSdio->RequestType == NVDDK_SDIO_MEMORY_ABORT_REQUEST) - { - pCommand.CmdArgument = 0; - pCommand.CommandCode = 12; - pCommand.ResponseType = NvDdkSdioRespType_R1b; - } - else - { - pCommand.CmdArgument = 0x80000C01; - pCommand.CommandCode = 52; - pCommand.ResponseType = NvDdkSdioRespType_R5; - } - - pCommand.CommandType = NvDdkSdioCommandType_Abort; - pCommand.IsDataCommand = NV_FALSE; - - Error = NvDdkSdioSendCommand(hSdio, &pCommand, &status); - if (Error != NvSuccess) - { - NV_DEBUG_PRINTF(("PrivSdioAbort: Failed to send command abort command \n")); - } - else - { - Error = NvOsSemaphoreWaitTimeout(hSdio->PrivSdioSema, - NVDDK_SDMMC_ABORT_TIMEOUT_MSEC); - if (Error != NvSuccess) - { - NV_DEBUG_PRINTF(("PrivSdioAbort: abort command timeout, Non Recoverable error \n")); - //Reset the controller - NvRmModuleReset(hSdio->hRm, NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance)); - } - } - -} - -void PrivSdioReset(NvDdkSdioDeviceHandle hSdio) -{ - NvU32 val = 0; - NvU32 Timeout = 0; - - // issue soft reset for both command and dat lines - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_CMD_LINE, RESETED, val); - val = NV_FLD_SET_DRF_DEF(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_DAT_LINE, RESETED, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, val); - - // For AP15 we need to wait for sometime for the information to synchronize - if (!hSdio->IsSdControllerVersion2) - { - NvOsWaitUS(SDMMC_SOFT_RESET_DELAY_USEC); - } - else - { - while ((!val) && (Timeout != SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_USEC)) - { - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, - SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL); - val = NV_DRF_VAL(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_CMD_LINE, val); - if (val) - { - val = NV_DRF_VAL(SDMMC, SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL, - SW_RESET_FOR_DAT_LINE, val); - } - NvOsWaitUS(SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_STEP_USEC); - Timeout += SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_STEP_USEC; - } - if (Timeout == SW_RESET_TIMEOUT_CTRL_CLOCK_CONTROL_USEC) - { - SD_PRINT(("SDIO_DDK COMD and DAT line reset failed\n")); - } - } -} - -void ConfigureInterrupts(NvDdkSdioDeviceHandle hSdio, NvU32 IntrEnableMask, NvU32 IntrDisableMask, NvU32 IntrStatusEnableMask) -{ - NvU32 val = 0; - - NvOsIntrMutexLock(hSdio->SdioThreadSafetyMutex); - - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS_ENABLE); - val |= IntrEnableMask; - val &= ~IntrDisableMask; - - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_STATUS_ENABLE, (val |IntrStatusEnableMask)); - - #if !NV_OAL - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, INTERRUPT_SIGNAL_ENABLE); - val |= IntrEnableMask; - val &= ~IntrDisableMask; - - SDMMC_REGW(hSdio->pSdioVirtualAddress, INTERRUPT_SIGNAL_ENABLE, val); - #endif - - NvOsIntrMutexUnlock(hSdio->SdioThreadSafetyMutex); - -} - -void - NvDdkSdioEnableIoMode( - NvDdkSdioDeviceHandle hSdio, - NvBool IsAcceptCardEvents) -{ - NvU32 val = 0; - - NV_ASSERT(hSdio); - if (IsAcceptCardEvents == NV_TRUE) - { - ConfigureInterrupts(hSdio, NvDdkSdioCommandStatus_Card, 0, 0); - if (hSdio->IsSdControllerVersion2) - { - // enable the interrupt at block gap - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - val = NV_FLD_SET_DRF_DEF(SDMMC, POWER_CONTROL_HOST, - INTERRUPT_AT_BLOCK_GAP, ENABLE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST, val); - } - } - else - { - ConfigureInterrupts(hSdio, 0, NvDdkSdioCommandStatus_Card, 0); - if (hSdio->IsSdControllerVersion2) - { - // disable the interrupt at block gap - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST); - val = NV_FLD_SET_DRF_DEF(SDMMC, POWER_CONTROL_HOST, - INTERRUPT_AT_BLOCK_GAP, DISABLE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, POWER_CONTROL_HOST, val); - } - } - hSdio->IsAcceptCardEvents = IsAcceptCardEvents; -} - -void NvDdkSdioSuspend(NvDdkSdioDeviceHandle hSdio, NvBool SwitchOffSDDevice) -{ - NvRmFreqKHz pConfiguredFrequencyKHz = 0; - NvRmFreqKHz SdioCurrentFreqKHz = 0; - NvU32 val = 0; - - - // switch off the voltage to the sd device - if (SwitchOffSDDevice == NV_TRUE) - { - NvOdmSdioSuspend(hSdio->SdioOdmHandle); - } - - if (!hSdio->ISControllerSuspended) - { - if (hSdio->IsSdControllerVersion2) - { - // remove the card clock - SdioEnableCardClock(hSdio, NV_FALSE); - - // Disable SDMMC_CLK bit in VENDOR_CLOCK_CONTROL register - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, VENDOR_CLOCK_CNTRL); - val = NV_FLD_SET_DRF_DEF(SDMMC, VENDOR_CLOCK_CNTRL, - SDMMC_CLK, DISABLE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, VENDOR_CLOCK_CNTRL, val); - - // disable clock to sdio controller - NvRmPowerModuleClockControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NV_FALSE); - } - else - { - SdioCurrentFreqKHz = hSdio->ConfiguredFrequency; - // Reduce clock to the lowest frequency, to support IO card interrupt detection - // even when the sdio driver is suspended( provided system is not in LP0) - NV_ASSERT_SUCCESS(NvDdkSdioSetClockFrequency( - hSdio, - SDMMC_LOW_POWER_FREQ_KHZ, - &pConfiguredFrequencyKHz)); - hSdio->ConfiguredFrequency = SdioCurrentFreqKHz; - } - - /* Report RM to disable power */ - NV_ASSERT_SUCCESS(NvRmPowerVoltageControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NvRmVoltsOff, - NvRmVoltsOff, - NULL, - 0, - NULL)); - hSdio->ISControllerSuspended = NV_TRUE; - } -} - -NvError -NvDdkSdioResume( - NvDdkSdioDeviceHandle hSdio, - NvBool IsCardInserted, - NvBool SwitchOnSDDevice) -{ - NvError e = NvSuccess; - NvBool IsClkStable = NV_FALSE; - NvRmFreqKHz pConfiguredFrequencyKHz = 0; - NvRmPowerEvent Event = NvRmPowerEvent_NoEvent; - NvBool IsReset = NV_FALSE; - NvU32 val = 0; - - // switch on the voltage to the sd device - if (SwitchOnSDDevice == NV_TRUE) - { - if (NV_TRUE != NvOdmSdioResume(hSdio->SdioOdmHandle)) - { - NV_ASSERT(!"SdioOdm Resume Failed"); - } - } - - /* enable power */ - NV_CHECK_ERROR_CLEANUP(NvRmPowerVoltageControl(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NvRmVoltsUnspecified, - NvRmVoltsUnspecified, - NULL, - 0, - NULL)); - - // now enable clock to sdio controller - NV_CHECK_ERROR_CLEANUP(NvRmPowerModuleClockControl( - hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance), - hSdio->SdioRmPowerClientId, - NV_TRUE)); -#if !NV_OAL - NV_CHECK_ERROR_CLEANUP(NvRmPowerGetEvent( - hSdio->hRm, - hSdio->SdioRmPowerClientId, - &Event )); -#endif - if (IsCardInserted == NV_TRUE) - { - NvRmModuleReset(hSdio->hRm, - NVRM_MODULE_ID(NvRmModuleID_Sdio, hSdio->Instance)); - IsReset = SdioIsReset(hSdio); - if (IsReset == NV_FALSE) - { - goto fail; - } - hSdio->BusWidth = NvDdkSdioDataWidth_1Bit; - } - - // enable internal clock to sdio - IsClkStable = SdioEnableInternalClock(hSdio); - if (IsClkStable == NV_FALSE) - { - goto fail; - } - - if (hSdio->IsSdControllerVersion2) - { - // enable the card clock - NV_CHECK_ERROR_CLEANUP(SdioEnableCardClock(hSdio, NV_TRUE)); - - // Enable SDMMC_CLK bit in VENDOR_CLOCK_CONTROL register - val = SDMMC_REGR(hSdio->pSdioVirtualAddress, VENDOR_CLOCK_CNTRL); - val = NV_FLD_SET_DRF_DEF(SDMMC, VENDOR_CLOCK_CNTRL, - SDMMC_CLK, ENABLE, val); - SDMMC_REGW(hSdio->pSdioVirtualAddress, VENDOR_CLOCK_CNTRL, val); - } - - if ((Event == NvRmPowerEvent_WakeLP0) || (IsCardInserted == NV_TRUE)) - { - // After LP0 need to reinitialize following settings - - // Restore current voltage setting - NV_CHECK_ERROR_CLEANUP(NvDdkSdioSetSDBusVoltage(hSdio, hSdio->BusVoltage)); - - // enable sd bus power - NV_CHECK_ERROR_CLEANUP(SdioEnableBusPower(hSdio)); - - // Initialize the block size again - NV_CHECK_ERROR_CLEANUP(NvDdkSdioSetBlocksize(hSdio, SDMMC_DEFAULT_BLOCK_SIZE)); - - // set data timeout counter value - NV_CHECK_ERROR_CLEANUP(SdioSetDataTimeout(hSdio, SdioDataTimeout_COUNTER_128M)); - - - ConfigureInterrupts(hSdio, SDIO_INTERRUPTS, ~SDIO_INTERRUPTS, 0); - - NvDdkSdioEnableIoMode(hSdio, hSdio->IsAcceptCardEvents); - - // Restore current data width - NV_ASSERT_SUCCESS(NvDdkSdioSetHostBusWidth(hSdio, hSdio->BusWidth)); - } - - NV_CHECK_ERROR_CLEANUP(NvDdkSdioSetClockFrequency( - hSdio, - hSdio->ConfiguredFrequency, - &pConfiguredFrequencyKHz)); - - NV_CHECK_ERROR_CLEANUP(SdioConfigureCardClock(hSdio, NV_FALSE)); - - hSdio->ISControllerSuspended = NV_FALSE; - return NvSuccess; - - -fail: - NV_DEBUG_PRINTF(("resume failed [%x]\n", e)); - NV_ASSERT(!"Sdio DDK Resume Failed"); - - return e; -} - -static void -GpioInterruptHandler(void *arg) -{ -#if !NV_OAL - NvBool IsCardInserted = NV_TRUE; - NvError e = NvSuccess; - NvDdkSdioDeviceHandle hSdio = (NvDdkSdioDeviceHandle)arg; - - if (hSdio->CardEventsSema) - { - // Disable power to the slot if the card is not inserted - e = NvDdkSdioIsCardInserted(hSdio, &IsCardInserted); - if (e == NvSuccess) - { - if (IsCardInserted) - { - NvOdmSdioResume(hSdio->SdioOdmHandle); - } - else - { - NvOdmSdioSuspend(hSdio->SdioOdmHandle); - } - } - NvOsSemaphoreSignal(hSdio->CardEventsSema); - } - NvRmGpioInterruptDone(hSdio->GpioIntrHandle); -#endif -} - |