diff options
-rw-r--r-- | arch/arm/mach-tegra/include/nvddk_sdio.h | 785 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_sdio.c | 3285 | ||||
-rw-r--r-- | drivers/mmc/host/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mmc/host/Makefile | 2 | ||||
-rw-r--r-- | drivers/mmc/host/tegra_sdio.c | 578 |
6 files changed, 1 insertions, 4658 deletions
diff --git a/arch/arm/mach-tegra/include/nvddk_sdio.h b/arch/arm/mach-tegra/include/nvddk_sdio.h deleted file mode 100644 index bcbeea3a361b..000000000000 --- a/arch/arm/mach-tegra/include/nvddk_sdio.h +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Copyright (c) 2008-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 - * <b> NVIDIA Driver Development Kit: SDIO Interface</b> - * - * @b Description: SD memory (standard capacity as well - * as high capacity), SDIO, MMC interface. - */ - -/** - * @defgroup nvddk_sdio SDIO Controller Interface - * SD memory (standard capacity as well as high capacity), SDIO, MMC - * interface for controlling and managing SD/SDIO/MMC cards present - * in SD slots on handheld and embedded devices. - - * This interface provides methods to initialize the SD module, identify - * the type of the card present in the slot, and read or write data to the - * SD memory/SDIO card. NvDdkSdio also has power management capabilities - * - * @ingroup nvddk_modules - * - * @{ - */ - -#ifndef INCLUDED_NVDDKSDIO_H -#define INCLUDED_NVDDKSDIO_H - -#include "nvos.h" -#include "nvrm_init.h" -#include "nvrm_gpio.h" -#include "nvrm_power.h" -#include "nvddk_blockdev.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif /* __cplusplus */ - -/** - * Opaque handle for NvDdkSdio context. - */ -typedef struct NvDdkSdioInfoRec *NvDdkSdioDeviceHandle; - -/** - * Indicates the interface being used for the card, - * i.e., number of data lines used for data transfer. - */ -typedef enum -{ - /** Only D0 is used for the data transferl */ - NvDdkSdioDataWidth_1Bit = 0, - /** Data Lines D0-D3 used for data transfer. */ - NvDdkSdioDataWidth_4Bit, - /** Data Lines D0-D7 used for data transfer. */ - NvDdkSdioDataWidth_8Bit, - /** Ignore -- Forces compilers to make 32-bit enums. */ - NvDdkSdioDataWidth_Force32 = 0x7FFFFFFF -} NvDdkSdioDataWidth; - -/** - * Defines constants that indicate types of command - * for SDMMC/MMC cards. - */ -typedef enum -{ - /** Normal. */ - NvDdkSdioCommandType_Normal = 0, - /** Suspend. */ - NvDdkSdioCommandType_Suspend, - /** Resume. */ - NvDdkSdioCommandType_Resume, - /** Abort data operations. */ - NvDdkSdioCommandType_Abort, - /** Ignore -- Forces compilers to make 32-bit enums. */ - NvDdkSdioCommandType_Force32 = 0x7FFFFFFF -} NvDdkSdioCommandType; - -/** - * Defines constants that indicate types of command - * responses for SDMMC/MMC cards. - */ -typedef enum -{ - /// No response type. - NvDdkSdioRespType_NoResp = 1, - /// R1 response type. - NvDdkSdioRespType_R1, - /// R1b response type. - NvDdkSdioRespType_R1b, - /// R2 response type. - NvDdkSdioRespType_R2, - /// R3 response type. - NvDdkSdioRespType_R3, - /** Responses R4 and R5 are applicable only to SDIO devices. */ - NvDdkSdioRespType_R4, - /** Responses R4 and R5 are applicable only to SDIO devices. */ - NvDdkSdioRespType_R5, - /// R6 response type. - NvDdkSdioRespType_R6, - /// R7 response type. - NvDdkSdioRespType_R7, - /// Ignore -- Forces compilers to make 32-bit enums. - NvDdkSdioRespType_Force32 = 0x7FFFFFFF -} NvDdkSdioRespType; - -/** - * Defines constants that indicate the bus voltage for - * SDMMC card. - */ -typedef enum -{ - /** Invalid. */ - NvDdkSdioSDBusVoltage_invalid = 0, - /** 1.8 V. */ - NvDdkSdioSDBusVoltage_1_8 = 5, - /** 3.0 V. */ - NvDdkSdioSDBusVoltage_3_0 = 6, - /** 3.3 V. */ - NvDdkSdioSDBusVoltage_3_3 = 7, - /** Ignore -- Forces compilers to make 32-bit enums. */ - NvDdkSdioSDBusVoltage_Force32 = 0x7FFFFFFF -} NvDdkSdioSDBusVoltage; - -/** - * Defines constants that indicate status of the last sent - * SD command/operation. - */ -typedef enum -{ - /** No error. */ - NvDdkSdioCommandStatus_None = 0, - /** Error. */ - NvDdkSdioCommandStatus_Error = 0x200, - /** Card interrupt. */ - NvDdkSdioCommandStatus_Card = 0x100, - /** Card removal. */ - NvDdkSdioCommandStatus_CardRemoval = 0x80, - /** Card insertion. */ - NvDdkSdioCommandStatus_CardInsertion = 0x40, - /** Buffer read ready. */ - NvDdkSdioCommandStatus_BufferReadReady = 0x20, - /** Buffer write ready. */ - NvDdkSdioCommandStatus_BufferWriteReady = 0x10, - /** DMA boundary detected. */ - NvDdkSdioCommandStatus_DMA = 0x8, - /** Block gap event. */ - NvDdkSdioCommandStatus_BlockGapEvent = 0x4, - /** Transfer complete. */ - NvDdkSdioCommandStatus_TransferComplete = 0x2, - /** Command complete. */ - NvDdkSdioCommandStatus_CommandComplete = 0x1, - /** Ignore -- Forces compilers to make 32-bit enums. */ - NvDdkSdioCommandStatus_Force32 = 0x7FFFFFFF -} NvDdkSdioControllerStatus; - -/** - * Defines constants that indicate error status information as a result - * of the last sent SD command/operation. - */ - typedef enum -{ - /** No error. */ - NvDdkSdioError_None = 0, - /** Error interrupt. */ - NvDdkSdioError_Err = 0x8000, - /** Command timeout error. */ - NvDdkSdioError_CommandTimeout = 0x10000, - /** Command CRC error. */ - NvDdkSdioError_CommandCRC = 0x20000, - /** Command end bit error. */ - NvDdkSdioError_CommandEndBit = 0x40000, - /** Command index error. */ - NvDdkSdioError_CommandIndex = 0x80000, - /** Data timeout error. */ - NvDdkSdioError_DataTimeout = 0x100000, - /** Data CRC error. */ - NvDdkSdioError_DataCRC = 0x200000, - /** Data endbit error. */ - NvDdkSdioError_DataEndBit = 0x400000, - /** Current limit error. */ - NvDdkSdioError_CurrentLimit = 0x800000, - /** Auto CMD12 error. */ - NvDdkSdioError_AutoCMD12 = 0x1000000, - /** ADMA error. */ - NvDdkSdioError_ADMA = 0x2000000, - /** Target response error. */ - NvDdkSdioError_TargetResponse = 0x10000000, - /** Ceata error. */ - NvDdkSdioError_Ceata = 0x20000000, - /** Ignore -- Forces compilers to make 32-bit enums. */ - NvDdkSdioError_Force32 = 0x7FFFFFFF -} NvDdkSdioErrorStatus; - -/** - * SD memory command contains the command-related information. - * Will be passed from the upper layers using NvDdkSdio. - */ - typedef struct - { - /** Command code to be used for the current operation. */ - NvU32 CommandCode; - /** Command type (normal/resume/abort/suspend, etc.)*/ - NvDdkSdioCommandType CommandType; - /** Indicates whether this is a data/non-data command request. */ - NvBool IsDataCommand; - /** - * Command argument: In case of memory cards, argument will consist - * the card address and in case of SDIO cards the argument will consist of - * the argument value to be sent along with the commands CMD52/CMD53. - */ - NvU32 CmdArgument; - /** - * Command response: type of response expected to this command R1/R2/R3, etc. - * A response type also indicates the length of the reponse. For example, - * R1 type of response is 48 bits long. - */ - NvDdkSdioRespType ResponseType; - /** - * Block size in bytes. - */ - NvU32 BlockSize; - } NvDdkSdioCommand; - -/** - * SDIO status contains the read/write information. - * Will be passed from the upper layers using NvDdkSdio while read/write. - */ - typedef struct NvDdkSdioStatusRec - { - /** Error information for the current read/write operation. It can contain - * multiple values. - */ - volatile NvDdkSdioErrorStatus SDErrorStatus; - /** Status Information for the current read/write operation. It can contain - * multiple values. - */ - volatile NvDdkSdioControllerStatus SDControllerStatus; - } NvDdkSdioStatus; - -/** - * Indicates the data block size. - */ -typedef enum -{ - NvDdkSdioBlockSize_512Bytes = 0, - NvDdkSdioBlockSize_1024Bytes, - NvDdkSdioBlockSize_2048Bytes, - /** Ignore -- Forces compilers to make 32-bit enums. */ - NvDdkSdioBlockSize_Force32 = 0x7FFFFFFF -} NvDdkSdioBlockSize; - -/** - * Indicates the timeout clock unit. - */ -typedef enum -{ - NvDdkSdioTimeoutClk_KHz= 0, - NvDdkSdioTimeoutClk_MHz= 1, - /** Ignore -- Forces compilers to make 32-bit enums. */ - NvDdkSdioTimeoutClkUnit_Force32 = 0x7FFFFFFF -} NvDdkSdioTimeoutClkUnit; - - -typedef enum -{ - NvDdkSdioClkDivider_DIV_BASE = 0x0, - /// Base clock divided by 2. - NvDdkSdioClkDivider_DIV_2 = 0x1, - /// Base clock divided by 4. - NvDdkSdioClkDivider_DIV_4 = 0x2, - /// Base clock divided by 6. - NvDdkSdioClkDivider_DIV_8 = 0x4, - /// Base clock divided by 16. - NvDdkSdioClkDivider_DIV_16 = 0x8, - /// Base clock divided by 32. - NvDdkSdioClkDivider_DIV_32 = 0x10, - /// Base clock divided by 64. - NvDdkSdioClkDivider_DIV_64 = 0x20, - /// Base clock divided by 128. - NvDdkSdioClkDivider_DIV_128 = 0x40, - /// Base clock divided by 256. - NvDdkSdioClkDivider_DIV_256 = 0x80 -}NvDdkSdioClkDivider; - -typedef enum -{ - NVDDK_SDIO_NORMAL_REQUEST = 0, - NVDDK_SDIO_MEMORY_ABORT_REQUEST, - NVDDK_SDIO_IO_ABORT_REQUEST, - NVDDK_SDIO_SUSPEND_REQUEST, - NVDDK_SDIO_RESUME_REQUEST -} SdioRequestType; - -/** - * SD host capabilities contains the information specific to the host controller - * implementation. The host controller may implement these values as fixed or - * loaded from flash memory during power on initialization. - */ - typedef struct NvDdkSdioHostCapabilitiesRec - { - /// Holds the max instances supported. - NvU8 MaxInstances; - - NvBool IsAutoCMD12Supported; - /// Holds a flag indicating whether the instance is being powered from the AO domain. - NvBool AlwaysON; - /// Holds a flag indicating whether the host controller is version 2. - NvBool IsSdControllerVersion2; - /// Holds teh bus voltage supported by the host controller. - NvDdkSdioSDBusVoltage BusVoltage; - /// Holds the maximum block size supported by the controller. - NvU32 MaxBlockLength; - }NvDdkSdioHostCapabilities; - - typedef struct NvDdkSdioInterfaceCapabilitiesRec -{ - /// Maximum bus width supported by the physical interface. - /// Will be 2, 4, or 8 depending on the selected pin mux. - NvU32 MmcInterfaceWidth; - - /// SDIO card HW settling time after reset, i.e. before reading the OCR. - NvU32 SDIOCardSettlingDelayMSec; -} NvDdkSdioInterfaceCapabilities; - -/// Function to get log2 of a power of 2. -/// When argument Val is not power of 2, log2 of the next -/// smaller power of 2 is returned -NvU8 SdUtilGetLog2(NvU32 Val); - -/** - * Get the SD host controller and SD interface capabilities. - * - * This API fills the SDIO host controller capabilities and - * SDIO interface capabilities. - * - * @param hDevice the Rm device handle - * @param pHostCap A pointer to SDIO host controlelr capabilities struct. - * @param pInterfaceCap A pointer to SDIO interface capabilities struct. - * @param instance The particular SDIO instance. - * @retval NvSuccess Success. - */ -NvError -NvDdkSdioGetCapabilities( - NvRmDeviceHandle hDevice, - NvDdkSdioHostCapabilities *pHostCap, - NvDdkSdioInterfaceCapabilities *pInterfaceCap, - NvU32 instance); - -/** - * Initializes the HW SD module. - * Allocates the resources needed for the SD data transfer operations. - * Allocates the device handle for subsequent use. This API can be called - * multiple times, to open various instances of the SDIO controller. This API - * associates an instance of the SDIO controller to an SDIO handle. After the - * client acquires an SDIO handle, it can use it for all further operations. - * - * @see NvDdkSdioClose - * - * @pre This method must be called before any other NvDdkSdio APIs. - * - * @param hDevice The RM device handle. - * @param hGpio The GPIO device handle, used for card interrupts. - * @param phSdio A pointer to the device handle - * @param pNotificationSema A pointer to the sempahore that will be used by - * SDIO module to signal notifications to the - * client. - * @param pCardEventsSema A pointer to the semaphore that will be used by - * the GPIO module to signal card events like - * card insertion/removal. - * @param Instance The particular SDIO instance. - * To the client, this covers command completion event, error event, - * and card removal event notification to the client. - * - * @retval NvSuccess Open device successful. - * @retval NvError_SdioInstanceTaken The requested instance is - * already been taken. - * @retval NvError_InsufficientMemory Cannot allocate memory. - */ -NvError -NvDdkSdioOpen( - NvRmDeviceHandle hDevice, - NvRmGpioHandle hGpio, - NvDdkSdioDeviceHandle *phSdio, - NvOsSemaphoreHandle *pNotificationSema, - NvOsSemaphoreHandle *pCardEventsSema, - NvU8 Instance); - -/** - * Deinitializes the HW SD module. - * Closes all the opened handles and release all the allocated resources for SD. - * @see NvDdkSdioOpen - * @param hSdio The SDIO device handle. - */ -void NvDdkSdioClose(NvDdkSdioDeviceHandle hSdio); - -/** - * Sends non-data commands to the card. If the command is an abort - * command, DAT and CMD lines will be reset using software reset register. - * This command returns after succesfully sending a command. This API - * waits until command inhibit (DAT) and command inhibit (CMD) both become - * 0 and then sends the current command. - * @param hSdio The device handle. - * @param pCommand A pointer to the ::NvDdkSdioCommand struct, - * which contains information like command index, - * response type, argument, etc. - * @param SdioStatus The SDIO status. - * @retval NvSuccess Success. - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen() first. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError -NvDdkSdioSendCommand( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioCommand *pCommand, - NvU32* SdioStatus); - -/** - * Reads the response from SDMMC controller. - * - * @param hSdio The device handle. - * @param CommandNumber Command number. - * @param ResponseType Type of response. - * @param pResponse A pointer to the response buffer. - * - * @retval NvSuccess Success. - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen() first. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError -NvDdkSdioGetCommandResponse( - NvDdkSdioDeviceHandle hSdio, - NvU32 CommandNumber, - NvDdkSdioRespType ResponseType, - NvU32 *pResponse); - -/** - * Reads the data from SD/SDIO card into \a pReadBuffer. - * - * @pre The SD module must be mounted using NvDdkSdioOpen() before - * using this method. - * - * @param hSdio The device handle. - * @param NumOfBytesToRead Number of bytes to read from the card. - * @param pReadBuffer A pointer to the application buffer in which data - * is read. - * @param pRWRequest A pointer to SD RW request struct. - * @param HWAutoCMD12Enable Flag to indicate if auto CMD12 is to be used. - * This flag can be ignored for SDIO cards. - * @param SdioStatus The SDIO status. - * @retval NvSuccess Identification successful. - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen() first. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError -NvDdkSdioRead( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfBytesToRead, - void *pReadBuffer, - NvDdkSdioCommand *pRWRequest, - NvBool HWAutoCMD12Enable, - NvU32* SdioStatus); - -/** - * Used to write data from \a pWriteBuffer on SD/SDIO card. - * - * @pre The SD module needs to be mounted using NvDdkSdioOpen() before - * using this method. - * - * @param hSdio The device handle. - * @param NumOfBytesToWrite Number of bytes to write. - * @param pWriteBuffer A pointer to the application buffer from which - * data is taken and written on card. - * @param pRWCommand A pointer to SD read/write command. - * @param HWAutoCMD12Enable Flag to indicate if auto CMD12 is to be used. - * This flag can be ignored for SDIO cards. - * @param SdioStatus The SDIO status. - * @retval NvSuccess Identification successful. - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen first(). - * @retval NvError_SdioCardNotPresent Card not present in slot. - * @retval NvError_SdioCardWriteProtected Card is write protected - * (for SD memory cards only). - */ -NvError -NvDdkSdioWrite( - NvDdkSdioDeviceHandle hSdio, - NvU32 NumOfBytesToWrite, - void *pWriteBuffer, - NvDdkSdioCommand *pRWCommand, - NvBool HWAutoCMD12Enable, - NvU32* SdioStatus); - -/** - * Gets write protect status (for memory/combo cards only). - * There is a write protect switch present for SD memory cards - * or mini/micro SD card adapters. These switches are used to restrict - * writes to the memory card. The upper layers using NvDdkSdio have to - * use this function to see whether the memory card is write-protected. - * @param hSdio The device handle. - * @param hGpio The GPIO device handle. - * @param IsWriteprotected A pointer to information whether the card is - * write protected (NV_TRUE) - or write enabled (NV_FALSE). - * @retval NvSuccess Operation successful. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError -NvDdkSdioIsWriteProtected( - NvDdkSdioDeviceHandle hSdio, - NvRmGpioHandle hGpio, - NvBool *IsWriteprotected); - - -/** - * Set the voltage level for the card - * operations. - * @param hSdio The device handle. - * @param Voltage Enum for voltage. - * @retval NvSuccess Success. - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen() first. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError -NvDdkSdioSetSDBusVoltage( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioSDBusVoltage Voltage); - -/** - * Enables high speed mode for SD high speed card - * operations. Before setting this bit, the host driver shall check the high - * speed support in the capabilities register. if this bit is set to 0 - * (default), the host controller outputs CMD line and DAT lines at the falling - * edge of the SD clock (up to 25 MHz). If this bit is set to 1, the host - * controller outputs CMD line and DAT lines at the rising edge of the SD clock - * (up to 50 MHz). - * @param hSdio The device handle. - * @retval NvSuccess Success. - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen() first. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError NvDdkSdioHighSpeedEnable(NvDdkSdioDeviceHandle hSdio); - -/** - * Disables high speed mode for SD high speed cards. - * The host controller outputs CMD line and DAT lines at the falling - * edge of the SD Clock (up to 25 MHz). - * - * @param hSdio The device handle. - * @retval NvSuccess Success. - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen() first. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError NvDdkSdioHighSpeedDisable(NvDdkSdioDeviceHandle hSdio); - -/** - * Set clock rate for the card. Upper layers using - * NvDdkSdio have to use this function to set the clock rate - * to be used for subsequent data transfer - * operations. - * @param hSdio The device handle. - * @param FrequencyKHz SD Clock Frequency to be configured. - * @param pConfiguredFrequencyKHz This field is updated with the - * actual frequency configured by the driver.. - * @retval NvSuccess Success - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen() first. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError -NvDdkSdioSetClockFrequency( - NvDdkSdioDeviceHandle hSdio, - NvRmFreqKHz FrequencyKHz, - NvRmFreqKHz* pConfiguredFrequencyKHz); - -/** - * Sets host controller bus width for the subsequent data operations. - * By default the bus width is set to 1-bit mode. - * SD Memory card is set to 4-bit mode when the it has to go in the - * data transfer mode for fast data transfer. - * Low speed SDIO cards do not support high data rate operations - * (4-bit data mode) and so card capability must - * be checked to see if card is a low speed card before setting the bus - * width for the card to 4 bits. If a card does not support 4-bit mode - * and this API is used to set its bus width to 4 bit mode, - * assert is encountered in debug mode. - * - * - * @param hSdio The device handle. - * @param CardDataWidth 1 or 4 bit mode. - * @retval NvSuccess Success. - * @retval NvError_SdioDeviceNotMounted Module not mounted. Need to - * call NvDdkSdioOpen() first. - * @retval NvError_SdioCardNotPresent Card not present in slot. - */ -NvError -NvDdkSdioSetHostBusWidth( - NvDdkSdioDeviceHandle hSdio, - NvDdkSdioDataWidth CardDataWidth); - -/** - * Checks the present state register to see if the card has been - * actually inserted. If NV_TRUE is returned, then it is safe to apply SD clock - * to the card. - * @param hSdio The device handle. - * @param IsCardInserted A pointer to information whether the card is - * inserted (NV_TRUE) - or removed (NV_FALSE). - * @retval NvSuccess Card detect feature present. - * @retval NvError_SdioCardAlwaysPresent Card is soldered on the board. - * @retval NvError_SdioAutoDetectCard Auto detect the card by sending the commands. - */ -NvError -NvDdkSdioIsCardInserted( - NvDdkSdioDeviceHandle hSdio, - NvBool *IsCardInserted); - -/** - * Resets the host controller by setting the software reset - * for all bit in the software reset register. - * @param hSdio The device handle. - */ -void NvDdkSdioResetController(NvDdkSdioDeviceHandle hSdio); - -/** - * Sets the blocksize of the host controller. - * This API should be called after the blocksize is set on the SD device - * using CMD16. - * - * @param hSdio The device handle. - * @param Blocksize The blocksize to be set in bytes. - * - * @retval NvSuccess Indicates the operation succeeded. - * @retval NvError_NotInitialized Indicates that the SDIO was not opened. - * @retval NvError_SdioControllerBusy Indicates the controller is busy carrying out - * read/write operation. - */ -NvError NvDdkSdioSetBlocksize(NvDdkSdioDeviceHandle hSdio, NvU32 Blocksize); - -/** - * Enables the SDIO host controller to accept the events generated by the I/O card. - * - * @param hSdio The device handle. - * @param IsAcceptCardEvents Flag to know whether or not to accept the card - * events. - */ -void - NvDdkSdioEnableIoMode( - NvDdkSdioDeviceHandle hSdio, - NvBool IsAcceptCardEvents); - -/** - * Part of static power management, call this API to put the SDIO controller - * into suspend state. This API is a mechanism for the client to augment OS power - * management policy. - * - * The H/W context of the SDIO controller is saved. Clock is disabled and power - * is also disabled to the controller. - * - * - * @param hSdio The SDIO device handle. - * @param SwitchOffSDDevice If NV_TRUE, switches off the voltage to the SD device. - * (like sd card or wifi module). If NV_FALSE, does not switch off the voltage to the SD device. - * - */ -void NvDdkSdioSuspend(NvDdkSdioDeviceHandle hSdio, NvBool SwitchOffSDDevice); - - -/** - * Part of static power management, call this API to wake the SDIO controller - * from suspend state. This API is a mechanism for the client to augment OS - * power management policy. - * - * The H/W context of the SDIO controller is restored. Clock is enabled and power - * is also enabled to the controller. - * - * - * @param hSdio The SDIO device handle. - * @param IsCardInserted Flag to indicate whether the following is API is - * called during the card insertion or in normal operation. - * @param SwitchOnSDDevice If NV_TRUE, switches on the voltage to the SD device. - * (like SD card or Wi-Fi module). If NV_FALSE, does not change the voltage to the SD device. - * - * @retval NvSuccess Success. - */ -NvError -NvDdkSdioResume( - NvDdkSdioDeviceHandle hSdio, - NvBool IsCardInserted, - NvBool SwitchOnSDDevice); - -/** - * Aborts the SDIO memory or I/O operation. - * - * @param hSdio The SDIO device handle. - * @param RequestType The type of abort request. - * @param FunctionNumber Function number of the SDIO module. - */ - void -NvDdkSdioAbort( - NvDdkSdioDeviceHandle hSdio, - SdioRequestType RequestType, - NvU32 FunctionNumber); - -/** - * Allocates the required resources, powers on the device, and - * prepares the device for I/O operations. - * Client gets a valid handle only if the device is found. - * The same handle must be used for further operations. - * The device can be opened by only one client at a time. - * - * @pre This method must be called once before using other - * NvDdkBlockDev APIs. - * - * @param Instance Instance of specific device. - * @param MinorInstance Minor instance of specific device. - * @param phBlockDev Returns pointer to device handle. - * - * @retval NvSuccess Device is present and ready for I/O operations. - * @retval NvError_BadParameter One or more of the arguments provided - * are incorrect. - * @retval NvError_SdioCardNotPresent SD card is not present or unsupported. - * @retval NvError_NotSupported The requested instance is not supported. - * @retval NvError_SdioCommandFailed SD card is not responding. - * @retval NvError_SdioInstanceTaken The requested instance is unavailable - * or already in use. - * @retval NvError_InsufficientMemory Cannot allocate memory. - */ -NvError -NvDdkSdBlockDevOpen( - NvU32 Instance, - NvU32 MinorInstance, - NvDdkBlockDevHandle *phBlockDev); - -NvError -NvDdkSdBlockDevInit(NvRmDeviceHandle hDevice); - -void -NvDdkSdBlockDevDeinit(void); - -#if defined(__cplusplus) -} -#endif /* __cplusplus */ - -/** @} */ - -#endif /* INCLUDED_NVDDKSDIO_H */ - diff --git a/arch/arm/mach-tegra/nvddk/Makefile b/arch/arm/mach-tegra/nvddk/Makefile index 1716bf866abe..f1b5da42d5c8 100644 --- a/arch/arm/mach-tegra/nvddk/Makefile +++ b/arch/arm/mach-tegra/nvddk/Makefile @@ -18,5 +18,4 @@ endif obj-$(CONFIG_MTD_NAND_TEGRA) += nvddk_nand.o -obj-$(CONFIG_MMC_TEGRA_SDIO) += nvddk_sdio.o obj-$(CONFIG_TEGRA_SNOR) += nvsnor_controller.o 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 -} - diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 4b93bc4a82f0..a87c6a1aa974 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -67,14 +67,6 @@ config MMC_SDHCI_TEGRA This enables the internal SDHCI-compatible interfaces in NVIDIA Tegra SoCs -config MMC_TEGRA_SDIO - boolean "MMC support for SDIO interface on NVIDIA Tegra SoCs" - depends on ARCH_TEGRA_1x_SOC && MACH_TEGRA_GENERIC - help - This enables the SDIO interface on NVIDIA Tegra SoCs - - - config MMC_RICOH_MMC tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)" depends on MMC_SDHCI_PCI diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index b95a3e450adc..2213463550ff 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -28,4 +28,4 @@ endif obj-$(CONFIG_MMC_S3C) += s3cmci.o obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o -obj-$(CONFIG_MMC_TEGRA_SDIO) += tegra_sdio.o + diff --git a/drivers/mmc/host/tegra_sdio.c b/drivers/mmc/host/tegra_sdio.c deleted file mode 100644 index 1503287880ec..000000000000 --- a/drivers/mmc/host/tegra_sdio.c +++ /dev/null @@ -1,578 +0,0 @@ -/* - * drivers/mmc/host/tegra_sdio.c - * - * MMC host driver for NVIDIA Tegra SoCs using NvDdk and NvRm APIs - * - * Copyright (C) 2009 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -// #define DEBUG -// #define VERBOSE_DEBUG - -/* - * TODO: - * 1. Revisit locking - * 2. use zero-copy DMA instead of buffer copy. - * 3. Detect card removal properly and handle the trasactions on the fly - * 4. Don't know how to enable SD card irq. - * 5. Some of the values like max clock, voltages supported and bit rates are - * hard coded. Need to get those from DDK. - */ - - -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/workqueue.h> -#include <linux/kthread.h> - -#include <linux/mmc/host.h> - -#include "mach/nvrm_linux.h" -#include "nvddk_sdio.h" -#include "nvos.h" -#include "nvodm_sdio.h" - -#define DRIVER_DESC "Nvidia Tegra SDIO/SD driver" -#define DRIVER_NAME "tegra_sdio" - -#ifdef VERBOSE_DEBUG -#define DBG(f, x...) \ - pr_info(DRIVER_NAME " [%s()]: " f, __func__,## x) -#else -#define DBG(f, x...) -#endif - -#define USE_SPINLOCK 0 - -#if USE_SPINLOCK -#define LOCK_T spinlock_t -#define CREATELOCK(_l) spin_lock_init(&(_l)) -#define DELETELOCK(_l) -#define LOCK(_l) spin_lock(&(_l)) -#define UNLOCK(_l) spin_unlock(&(_l)) -#define ATOMIC(_l,_f) spin_lock_irqsave(&(_l),(_f)) -#define UNATOMIC(_l,_f) spin_unlock_irqrestore(&(_l),(_f)) -#else -#define LOCK_T struct mutex -#define CREATELOCK(_l) mutex_init(&(_l)) -#define DELETELOCK(_l) -#define LOCK(_l) mutex_lock(&(_l)) -#define UNLOCK(_l) mutex_unlock(&(_l)) -#define ATOMIC(_l,_f) local_irq_save((_f)) -#define UNATOMIC(_l,_f) local_irq_restore((_f)) -#endif - -struct tegra_sdio_host{ - struct mmc_host *mmc; - struct platform_device *pdev; - LOCK_T Lock; - NvU32 Instance; - NvDdkSdioSDBusVoltage voltage; - struct work_struct Workqueue; - struct mmc_request *req; - NvBool bCardPresent; - NvDdkSdioDeviceHandle hDdk; - NvDdkSdioHostCapabilities hostCaps; - NvDdkSdioInterfaceCapabilities interfaceCaps; - NvOsSemaphoreHandle hSem; - NvOsSemaphoreHandle hCardSemaphore; - NvOdmSdioHandle hSdioHandle; - struct task_struct *cardDetectTask; - NvBool bKillCardDetectThread; - unsigned int clock; - unsigned int bus_width; - NvU32 StartOffset; -}; - -#ifdef VERBOSE_DEBUG -static void tegra_DumpPackets(struct mmc_data *data) -{ - void *addr = (void *)sg_virt(data->sg); - int i; - - for (i=0; i< sg_dma_len(data->sg); i++) { - if (!(i%8)) - printk("\n"); - printk("%x ", ((unsigned char *)addr)[i]); - } - printk("\n"); -} -#endif - -static int tegra_sdio_carddetect(void *arg) -{ - struct tegra_sdio_host *host = (struct tegra_sdio_host *)arg; - while (1) { - NvOsSemaphoreWait(host->hCardSemaphore); - if (host->bKillCardDetectThread) - break; - mmc_detect_change(host->mmc, 0); - } - return 0; -} - -static inline NvDdkSdioRespType tegra_ConvertRespType(struct mmc_command *cmd) -{ - NvDdkSdioRespType resp = 0; - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: - resp = NvDdkSdioRespType_NoResp; - break; - case MMC_RSP_R1: /* MMC_RSP_R5 & MMC_RSP_R6 */ - resp = NvDdkSdioRespType_R1; - break; - case MMC_RSP_R1B: - resp = NvDdkSdioRespType_R1b; - break; - case MMC_RSP_R2: - resp = NvDdkSdioRespType_R2; - break; - case MMC_RSP_R3: /* Same as MMC_RSP_R4 */ - resp = NvDdkSdioRespType_R3; - break; - default: - BUG_ON(1); - } - return resp; -} - - -static inline void tegra_GetRepsonse(struct tegra_sdio_host *host, - struct mmc_command *cmd) -{ - if (cmd->flags & MMC_RSP_136) { - int i; - NvU32 resp[4]; - NvDdkSdioGetCommandResponse(host->hDdk, 0, - tegra_ConvertRespType(cmd), resp); - - /* Re-format to the way the linux stack expects */ - for (i = 0;i < 4;i++) { - cmd->resp[i] = resp[3-i] << 8; - if (i != 3) - cmd->resp[i] |= ((NvU8 *)resp)[(3-i) * 4 -1]; - } - } else { - NvDdkSdioGetCommandResponse(host->hDdk, 0, - tegra_ConvertRespType(cmd), - (NvU32 *)(cmd->resp)); - } - return; -} - -// -// Work queue which does all the heavy lifting. -// - -static void tegra_sdio_wq(struct work_struct *w) -{ - struct tegra_sdio_host *host = container_of(w, struct tegra_sdio_host, - Workqueue); - struct mmc_request *req; - NvDdkSdioCommand cmd; - NvU32 status; - NvError err; - - LOCK(host->Lock); - - req = host->req; - - NvOsMemset(&cmd, 0, sizeof(cmd)); - cmd.CommandCode = req->cmd->opcode; - cmd.CommandType = NvDdkSdioCommandType_Normal; - cmd.CmdArgument = req->cmd->arg; - cmd.ResponseType = tegra_ConvertRespType(req->cmd); - if (req->data) { - struct mmc_data *data = req->data; - void *addr; - int sg_cnt; - int size; - NvBool cmd12Enable = NV_FALSE; - - /* FIXME only works for block addressing cards! */ - if (host->StartOffset) - cmd.CmdArgument += host->StartOffset >> 9; - - BUG_ON(data->blksz * data->blocks > 524288); - BUG_ON(data->blksz > host->mmc->max_blk_size); - BUG_ON(data->blocks > 65535); - - sg_cnt = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - DMA_BIDIRECTIONAL); - BUG_ON(sg_cnt != 1); - - cmd.IsDataCommand = NV_TRUE; - cmd.BlockSize = data->blksz; - if (data->stop) { - /* only support CMD12 of all the stop commands. - * This seems to work! - */ - if (data->stop->opcode == 12 && !data->stop->arg) { - cmd12Enable = NV_TRUE; - } else { - BUG_ON(1); - } - } - - size = data->blocks * data->blksz; - addr = (void *)sg_virt(data->sg); - - if (data->flags & MMC_DATA_READ) - err = NvDdkSdioRead(host->hDdk, size, addr, &cmd, - cmd12Enable, &status); - else - err = NvDdkSdioWrite(host->hDdk, size, addr, &cmd, - cmd12Enable, &status); - - if (err == NvSuccess && status == NvDdkSdioError_None) { - req->cmd->error = 0; - req->data->error = 0; - data->bytes_xfered = data->blksz * data->blocks; - - } else { - /* FIXME set the appropriate error code */ - DBG("Controller reported error 0x%x API error 0x%x\n", - status, err); - data->bytes_xfered = 0; - req->cmd->error = -EIO; - req->data->error = -EIO; - } - - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, DMA_BIDIRECTIONAL); - - tegra_GetRepsonse(host, req->cmd); - - } else { - cmd.IsDataCommand = NV_FALSE; - cmd.BlockSize = 512; - err = NvDdkSdioSendCommand(host->hDdk, &cmd, &status); - if (err == NvSuccess) { - if (status == NvDdkSdioError_None) - req->cmd->error = 0; - else - req->cmd->error = -EINVAL; - } else - DBG("DDK failed controller status = 0x%x\n", status); - - tegra_GetRepsonse(host, req->cmd); - } - - UNLOCK(host->Lock); - - host->req = NULL; - mmc_request_done(host->mmc, req); - return; -} - -// -// MMC callbacks -// - -static void tegra_sdio_request(struct mmc_host *mmc, struct mmc_request *req) -{ - struct tegra_sdio_host *host; - - host = mmc_priv(mmc); - - LOCK(host->Lock); - - host->req = req; - if (!host->bCardPresent) { - host->req->cmd->error = -ENOMEDIUM; - } - - schedule_work(&host->Workqueue); - UNLOCK(host->Lock); -} - -static int tegra_sdio_get_ro(struct mmc_host *mmc) -{ - struct tegra_sdio_host *host; - NvBool bIsWriteProtected = NV_FALSE; - NvError err; - - host = mmc_priv(mmc); - err = NvDdkSdioIsWriteProtected(host->hDdk, s_hGpioGlobal, - &bIsWriteProtected); - if (err != NvSuccess) { - pr_err(DRIVER_NAME "IsWriteProtected error(%d)\n", err); - if (err == NvError_SdioCardNotPresent) { - return 0; - } else { - return -ENOSYS; - } - } - return (bIsWriteProtected == NV_TRUE) ? 1 : 0; -} - - -static void tegra_sdio_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct tegra_sdio_host *host; - NvError err; - - host = mmc_priv(mmc); - - /* - * We first get the MMC_POWER_OFF, then MMC_POWER_UP and - * then the stack swtiches to the MMC_POWER_ON mode. - */ - if (ios->power_mode == MMC_POWER_OFF) { - /* How do we power off the controller and the io? */ - } - - /* Set the clock. FIXME DDK doesn't allow the clock to be set to 0 */ - if (ios->clock) { - if (ios->clock != host->clock) { - NvU32 configuredFreq; - err = NvDdkSdioSetClockFrequency(host->hDdk, - ios->clock/1000, &configuredFreq); - BUG_ON(err!=NvSuccess); - DBG("SDIO clock set to (%dKHz) req (%dKHz) err (%d)\n", - configuredFreq, ios->clock/1000, err); - host->clock = ios->clock; - } - } - - /* Set the bus width */ - if (host->bus_width != ios->bus_width) { - NvDdkSdioDataWidth width; - if (ios->bus_width == MMC_BUS_WIDTH_8) { - width = NvDdkSdioDataWidth_8Bit; - } else if (ios->bus_width == MMC_BUS_WIDTH_4) { - width = NvDdkSdioDataWidth_4Bit; - } else if (ios->bus_width == MMC_BUS_WIDTH_1) { - width = NvDdkSdioDataWidth_1Bit; - } else { - /* Got wrong parameters */ - width = 0; - BUG_ON(1); - } - NvDdkSdioSetHostBusWidth(host->hDdk, width); - host->bus_width = ios->bus_width; - } - - /* timming - is there any difference between SD high speed and mmc high - * speed? */ - if (ios->timing == MMC_TIMING_SD_HS || ios->timing == MMC_TIMING_SD_HS) - NvDdkSdioHighSpeedEnable(host->hDdk); - else - NvDdkSdioHighSpeedDisable(host->hDdk); - - return; -} - -static int tegra_sdio_cardpresent(struct mmc_host *mmc) -{ - struct tegra_sdio_host *host; - NvBool bIsCardPResent; - - host = mmc_priv(mmc); - NvDdkSdioIsCardInserted(host->hDdk, &bIsCardPResent); - - DBG("Sdio slot %s:%s\n", mmc_hostname(mmc), - ((bIsCardPResent == NV_TRUE) ? "full" : "empty")); - - return (bIsCardPResent == NV_TRUE) ? 1 : 0; -} - -static void tegra_sdio_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - /* FIXME what should we do here? */ - return; -} - -static struct mmc_host_ops tegra_sdio_ops = -{ - .request = tegra_sdio_request, - .set_ios = tegra_sdio_set_ios, - .get_ro = tegra_sdio_get_ro, - .get_cd = tegra_sdio_cardpresent, - .enable_sdio_irq = tegra_sdio_enable_sdio_irq, -}; - -static int -tegra_sdio_probe(struct platform_device *pdev) -{ - struct tegra_sdio_host *host = NULL; - struct mmc_host *mmc = NULL; - int ret = -ENODEV; - NvError err; - struct tegra_sdio_pdata *pdata = pdev->dev.platform_data; - - mmc = mmc_alloc_host(sizeof(struct tegra_sdio_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto fail; - } - - dev_set_drvdata(&pdev->dev, host); - - host = mmc_priv(mmc); - host->mmc = mmc; - host->pdev = pdev; - host->Instance = pdev->id; - host->voltage = NvDdkSdioSDBusVoltage_invalid; - CREATELOCK(host->Lock); - INIT_WORK(&host->Workqueue, tegra_sdio_wq); - host->hSdioHandle = NvOdmSdioOpen(pdev->id); - if (!host->hSdioHandle) { - goto fail; - } - NvDdkSdioGetCapabilities(s_hRmGlobal, &host->hostCaps, - &host->interfaceCaps, pdev->id); - - /* Set SD/MMC configuration */ - mmc->ops = &tegra_sdio_ops; - mmc->caps = 0; - if (host->interfaceCaps.MmcInterfaceWidth >= 4) { - mmc->caps |= MMC_CAP_4_BIT_DATA; - if (host->interfaceCaps.MmcInterfaceWidth == 8) { - mmc->caps |= MMC_CAP_8_BIT_DATA; - } - } - - mmc->caps |= MMC_CAP_SDIO_IRQ; - - /* Is there a caps bit to select if the controller supports high speed - * mode or not? */ - if (1) { - mmc->caps |= MMC_CAP_SD_HIGHSPEED; - mmc->caps |= MMC_CAP_MMC_HIGHSPEED; - } - - /* Supports upto to 52M i.e compliant to high speed and EMMC and - * SD specs */ - mmc->f_max = 52000000; - mmc->f_min = 400000; - mmc->max_seg_size = 524288; - mmc->max_req_size = 524288; - mmc->max_phys_segs = 128; - mmc->max_hw_segs = 1; - mmc->max_blk_size = 512; - mmc->max_blk_count = 65535; - - mmc->ocr_avail = 0; - mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; - - if ((NvOsSemaphoreCreate(&host->hCardSemaphore, 0) != NvSuccess) - || (NvOsSemaphoreCreate(&host->hSem, 0) != NvSuccess)) { - goto fail; - } - - host->bKillCardDetectThread = NV_FALSE; - host->cardDetectTask = kthread_create(tegra_sdio_carddetect, - (void *)host, "sdio_card_detect/%d", pdev->id); - if (IS_ERR(host->cardDetectTask)) { - goto fail; - } - wake_up_process( host->cardDetectTask ); - - err = NvDdkSdioOpen(s_hRmGlobal, s_hGpioGlobal, &host->hDdk, - &host->hSem, &host->hCardSemaphore, pdev->id); - if (err != NvSuccess) { - goto fail; - } - host->clock = 0; - host->bus_width = (unsigned int)-1; - if (pdata) - host->StartOffset = pdata->StartOffset; - - ret = mmc_add_host(mmc); - if (ret) { - dev_err(&pdev->dev, "failed to add mmc host\n"); - goto fail; - } - - platform_set_drvdata(pdev, mmc); - dev_info(&pdev->dev, "Initialization done\n"); - - return 0; - -fail: - if (host) { - if (host->cardDetectTask) { - host->bKillCardDetectThread = NV_TRUE; - NvOsSemaphoreSignal(host->hCardSemaphore); - (void)kthread_stop( host->cardDetectTask ); - } - if (host->hSem) - NvOsSemaphoreDestroy(host->hSem); - if (host->hCardSemaphore) - NvOsSemaphoreDestroy(host->hCardSemaphore); - if (host->hSdioHandle) - NvOdmSdioClose(host->hSdioHandle); - if (host->hDdk) - NvDdkSdioClose(host->hDdk); - } - if (mmc) - mmc_free_host(mmc); - - return ret; -} - -static int __devexit -tegra_sdio_remove(struct platform_device *pdev) -{ - struct tegra_sdio_host *host = dev_get_drvdata(&pdev->dev); - - if (!host) return 0; - - host->bKillCardDetectThread = NV_TRUE; - NvOsSemaphoreSignal(host->hCardSemaphore); - (void)kthread_stop( host->cardDetectTask ); - - if (host->hDdk) - NvDdkSdioClose(host->hDdk); - - if (host->hSdioHandle) - NvOdmSdioClose(host->hSdioHandle); - - mmc_free_host(host->mmc); - dev_set_drvdata(&pdev->dev, NULL); - return 0; -} - -static struct platform_driver tegra_sdio_driver = { - .probe = tegra_sdio_probe, - .remove = __devexit_p(tegra_sdio_remove), - .suspend = NULL, - .resume = NULL, - .driver = { - .name = "tegra-sdio", - .owner = THIS_MODULE, - }, -}; - -static int __init tegra_sdio_init(void) -{ - return platform_driver_register(&tegra_sdio_driver); -} - -static void __exit tegra_sdio_exit(void) -{ - platform_driver_unregister(&tegra_sdio_driver); -} - -module_init(tegra_sdio_init); -module_exit(tegra_sdio_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DRIVER_DESC); - |