diff --git a/XilinxProcessorIPLib/drivers/sdps/data/sdps.mdd b/XilinxProcessorIPLib/drivers/sdps/data/sdps.mdd new file mode 100755 index 00000000..c7c40d2e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/sdps/data/sdps.mdd @@ -0,0 +1,42 @@ +############################################################################### +# +# Copyright (C) 2013 - 2014 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +############################################################################### +OPTION psf_version = 2.1; + +BEGIN driver sdps + + OPTION supported_peripherals = (ps7_sdio psu_sd); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 2.5; + OPTION NAME = sdps; + +END driver diff --git a/XilinxProcessorIPLib/drivers/sdps/data/sdps.tcl b/XilinxProcessorIPLib/drivers/sdps/data/sdps.tcl new file mode 100755 index 00000000..0d66b093 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/sdps/data/sdps.tcl @@ -0,0 +1,53 @@ +############################################################################### +# +# Copyright (C) 2013 - 2014 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +############################################################################### +############################################################################## +# +# Modification History +# +# Ver Who Date Changes +# ----- ---- -------- ----------------------------------------------- +# 1.00a hk 10/17/13 First release +# 2.0 adk 12/10/13 Updated as per the New Tcl API's +# 2.4 sk 12/04/14 Added CD and WP parameters +# +############################################################################## + +#uses "xillib.tcl" + +proc generate {drv_handle} { + ::hsi::utils::define_zynq_include_file $drv_handle "xparameters.h" "XSdPs" "NUM_INSTANCES" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_SDIO_CLK_FREQ_HZ" "C_HAS_CD" "C_HAS_WP" + + ::hsi::utils::define_zynq_config_file $drv_handle "xsdps_g.c" "XSdPs" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_SDIO_CLK_FREQ_HZ" "C_HAS_CD" "C_HAS_WP" + + ::hsi::utils::define_zynq_canonical_xpars $drv_handle "xparameters.h" "XSdPs" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_SDIO_CLK_FREQ_HZ" "C_HAS_CD" "C_HAS_WP" + +} diff --git a/XilinxProcessorIPLib/drivers/sdps/src/Makefile b/XilinxProcessorIPLib/drivers/sdps/src/Makefile new file mode 100644 index 00000000..f57081af --- /dev/null +++ b/XilinxProcessorIPLib/drivers/sdps/src/Makefile @@ -0,0 +1,40 @@ +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +CC_FLAGS = $(COMPILER_FLAGS) +ECC_FLAGS = $(EXTRA_COMPILER_FLAGS) + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I./. -I${INCLUDEDIR} + +OUTS = *.o + +LIBSOURCES:=*.c +INCLUDEFILES:=*.h + +OBJECTS = $(addsuffix .o, $(basename $(wildcard *.c))) + +libs: banner xsdps_libs clean + +%.o: %.c + ${COMPILER} $(CC_FLAGS) $(ECC_FLAGS) $(INCLUDES) -o $@ $< + +banner: + echo "Compiling sdps" + +xsdps_libs: ${OBJECTS} + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OBJECTS} + +.PHONY: include +include: xsdps_includes + +xsdps_includes: + ${CP} ${INCLUDEFILES} ${INCLUDEDIR} + +clean: + rm -rf ${OBJECTS} diff --git a/XilinxProcessorIPLib/drivers/sdps/src/xsdps.c b/XilinxProcessorIPLib/drivers/sdps/src/xsdps.c new file mode 100644 index 00000000..7cb26db0 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/sdps/src/xsdps.c @@ -0,0 +1,1122 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps.c +* @addtogroup sdps_v2_4 +* @{ +* @details +* +* Contains the interface functions of the XSdPs driver. +* See xsdps.h for a detailed description of the device and driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.00a hk/sg 10/17/13 Initial release +* 2.0 hk 12/13/13 Added check for arm to use sleep.h and its API's +* 2.1 hk 04/18/14 Add sleep for microblaze designs. CR# 781117. +* 2.2 hk 07/28/14 Make changes to enable use of data cache. +* 2.3 sk 09/23/14 Send command for relative card address +* when re-initialization is done.CR# 819614. +* Use XSdPs_Change_ClkFreq API whenever changing +* clock.CR# 816586. +* 2.4 sk 12/04/14 Added support for micro SD without +* WP/CD. CR# 810655. +* Checked for DAT Inhibit mask instead of CMD +* Inhibit mask in Cmd Transfer API. +* Added Support for SD Card v1.0 +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xsdps.h" +/* + * The header sleep.h and API usleep() can only be used with an arm design. + * MB_Sleep() is used for microblaze design. + */ +#ifdef __arm__ + +#include "sleep.h" + +#endif + +#ifdef __MICROBLAZE__ + +#include "microblaze_sleep.h" + +#endif + +/************************** Constant Definitions *****************************/ +#define XSDPS_CMD8_VOL_PATTERN 0x1AA +#define XSDPS_RESPOCR_READY 0x80000000 +#define XSDPS_ACMD41_HCS 0x40000000 +#define XSDPS_ACMD41_3V3 0x00300000 +#define XSDPS_CMD1_HIGH_VOL 0x00FF8000 +#define XSDPS_CMD1_DUAL_VOL 0x00FF8010 + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define XSDPS_INIT_DELAY 2000 + +/************************** Function Prototypes ******************************/ +u32 XSdPs_FrameCmd(u32 Cmd); +int XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt); +void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff); + +/*****************************************************************************/ +/** +* +* Initializes a specific XSdPs instance such that the driver is ready to use. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param ConfigPtr is a reference to a structure containing information +* about a specific SD device. This function initializes an +* InstancePtr object for a specific device specified by the +* contents of Config. +* @param EffectiveAddr is the device base address in the virtual memory +* address space. The caller is responsible for keeping the address +* mapping from EffectiveAddr to the device physical base address +* unchanged once this function is invoked. Unexpected errors may +* occur if the address mapping changes after this function is +* called. If address translation is not used, use +* ConfigPtr->Config.BaseAddress for this device. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* It must be stopped to re-initialize. +* +* @note This function initializes the host controller. +* Initial clock of 400KHz is set. +* Voltage of 3.3V is selected as that is supported by host. +* Interrupts status is enabled and signal disabled by default. +* Default data direction is card to host and +* 32 bit ADMA2 is selected. Defualt Block size is 512 bytes. +* +******************************************************************************/ +int XSdPs_CfgInitialize(XSdPs *InstancePtr, XSdPs_Config *ConfigPtr, + u32 EffectiveAddr) +{ + u32 ClockReg; + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + + /* + * Set some default values. + */ + InstancePtr->Config.BaseAddress = EffectiveAddr; + InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz; + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + InstancePtr->Config.CardDetect = ConfigPtr->CardDetect; + InstancePtr->Config.WriteProtect = ConfigPtr->WriteProtect; + + /* + * "Software reset for all" is initiated + */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, XSDPS_SW_RST_OFFSET, + XSDPS_SWRST_ALL_MASK); + + /* + * Proceed with initialization only after reset is complete + */ + while (XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_SW_RST_OFFSET) & XSDPS_SWRST_ALL_MASK); + + /* + * Read capabilities register and update it in Instance pointer. + * It is sufficient to read this once on power on. + */ + InstancePtr->Host_Caps = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_CAPS_OFFSET); + + /* + * Select voltage and enable bus power. + */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_POWER_CTRL_OFFSET, + XSDPS_PC_BUS_VSEL_3V3_MASK | XSDPS_PC_BUS_PWR_MASK); + + /* + * Change the clock frequency to 400 KHz + */ + Status = XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_400_KHZ); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH ; + } + + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET, + XSDPS_HC_DMA_ADMA2_32_MASK); + + /* + * Enable all interrupt status except card interrupt initially + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_EN_OFFSET, + XSDPS_NORM_INTR_ALL_MASK & (~XSDPS_INTR_CARD_MASK)); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_EN_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + + /* + * Disable all interrupt signals by default. + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_SIG_EN_OFFSET, 0x0); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_SIG_EN_OFFSET, 0x0); + + /* + * Transfer mode register - default value + * DMA enabled, block count enabled, data direction card to host(read) + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DMA_EN_MASK | XSDPS_TM_BLK_CNT_EN_MASK | + XSDPS_TM_DAT_DIR_SEL_MASK); + + /* + * Set block size to 512 by default + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, XSDPS_BLK_SIZE_512_MASK); + + Status = XST_SUCCESS; + +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* SD initialization is done in this function +* +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because +* a) SD is already initialized +* b) There is no card inserted +* c) One of the steps (commands) in the + initialization cycle failed +* +* @note This function initializes the SD card by following its +* initialization and identification state diagram. +* CMD0 is sent to reset card. +* CMD8 and ACDM41 are sent to identify voltage and +* high capacity support +* CMD2 and CMD3 are sent to obtain Card ID and +* Relative card address respectively. +* CMD9 is sent to read the card specific data. +* +******************************************************************************/ +int XSdPs_SdCardInitialize(XSdPs *InstancePtr) +{ + u32 PresentStateReg; + u32 Status; + u32 RespOCR = 0x0; + u32 CSD[4]; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + if(InstancePtr->Config.CardDetect) { + /* + * Check the present state register to make sure + * card is inserted and detected by host controller + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* + * 74 CLK delay after card is powered up, before the first command. + */ + +#ifdef __arm__ + + usleep(XSDPS_INIT_DELAY); + +#endif + +#ifdef __MICROBLAZE__ + + /* 2 msec delay */ + MB_Sleep(2); + +#endif + + /* + * CMD0 no response expected + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD0, 0, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * CMD8; response expected + * 0x1AA - Supply Voltage 2.7 - 3.6V and AA is pattern + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD8, + XSDPS_CMD8_VOL_PATTERN, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + RespOCR = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + if (RespOCR != XSDPS_CMD8_VOL_PATTERN) { + InstancePtr->CardType = CT_SD1; + } + else { + InstancePtr->CardType = CT_SD2; + } + + RespOCR = 0; + /* + * Send ACMD41 while card is still busy with power up + */ + while ((RespOCR & XSDPS_RESPOCR_READY) == 0) { + Status = XSdPs_CmdTransfer(InstancePtr, CMD55, 0, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * 0x40300000 - Host High Capacity support & 3.3V window + */ + Status = XSdPs_CmdTransfer(InstancePtr, ACMD41, + (XSDPS_ACMD41_HCS | XSDPS_ACMD41_3V3), 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Response with card capacity + */ + RespOCR = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + } + + /* + * Update HCS support flag based on card capacity response + */ + if (RespOCR & XSDPS_ACMD41_HCS) + InstancePtr->HCS = 1; + + /* + * CMD2 for Card ID + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD2, 0, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + InstancePtr->CardID[0] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + InstancePtr->CardID[1] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP1_OFFSET); + InstancePtr->CardID[2] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP2_OFFSET); + InstancePtr->CardID[3] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP3_OFFSET); + do { + Status = XSdPs_CmdTransfer(InstancePtr, CMD3, 0, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Relative card address is stored as the upper 16 bits + * This is to avoid shifting when sending commands + */ + InstancePtr->RelCardAddr = + XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET) & 0xFFFF0000; + } while (InstancePtr->RelCardAddr == 0); + + Status = XSdPs_CmdTransfer(InstancePtr, CMD9, (InstancePtr->RelCardAddr), 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Card specific data is read. + * Currently not used for any operation. + */ + CSD[0] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + CSD[1] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP1_OFFSET); + CSD[2] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP2_OFFSET); + CSD[3] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP3_OFFSET); + + Status = XST_SUCCESS; + +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* This function does SD command generation. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Cmd is the command to be sent. +* @param Arg is the argument to be sent along with the command. +* This could be address or any other information +* @param BlkCnt - Block count passed by the user. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because another transfer +* is in progress or command or data inhibit is set +* +******************************************************************************/ +int XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt) +{ + u32 PresentStateReg; + u32 CommandReg; + u32 StatusReg; + u32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Check the command inhibit to make sure no other + * command transfer is in progress + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if (PresentStateReg & XSDPS_PSR_INHIBIT_CMD_MASK) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Write block count register + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_CNT_OFFSET, BlkCnt); + + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_TIMEOUT_CTRL_OFFSET, 0xE); + + /* + * Write argument register + */ + XSdPs_WriteReg(InstancePtr->Config.BaseAddress, + XSDPS_ARGMT_OFFSET, Arg); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_NORM_INTR_ALL_MASK); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, XSDPS_ERROR_INTR_ALL_MASK); + /* + * Command register is set to trigger transfer of command + */ + CommandReg = XSdPs_FrameCmd(Cmd); + + /* + * Mask to avoid writing to reserved bits 31-30 + * This is necessary because 0x80000000 is used by this software to + * distinguish between ACMD and CMD of same number + */ + CommandReg = CommandReg & 0x3FFF; + + /* + * Check for data inhibit in case of command using DAT lines + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_INHIBIT_DAT_MASK) && + (CommandReg & XSDPS_DAT_PRESENT_SEL_MASK)) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CMD_OFFSET, + CommandReg); + + /* + * Polling for response for now + */ + do { + StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET); + + if (StatusReg & XSDPS_INTR_ERR_MASK) { + + /* + * Write to clear error bits + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + Status = XST_FAILURE; + goto RETURN_PATH; + } + } while((StatusReg & XSDPS_INTR_CC_MASK) == 0); + /* + * Write to clear bit + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, + XSDPS_INTR_CC_MASK); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* This function frames the Command register for a particular command. +* Note that this generates only the command register value i.e. +* the upper 16 bits of the transfer mode and command register. +* This value is already shifted to be upper 16 bits and can be directly +* OR'ed with transfer mode register value. +* +* @param Command to be sent. +* +* @return Command register value complete with response type and +* data, CRC and index related flags. +* +******************************************************************************/ +u32 XSdPs_FrameCmd(u32 Cmd) +{ + u32 RetVal; + + RetVal = Cmd; + + switch(Cmd) { + case CMD0: + RetVal |= RESP_NONE; + break; + case CMD1: + RetVal |= RESP_R3; + break; + case CMD2: + RetVal |= RESP_R2; + break; + case CMD3: + RetVal |= RESP_R6; + break; + case CMD4: + RetVal |= RESP_NONE; + break; + case CMD5: + RetVal |= RESP_R1B; + break; + +#ifndef MMC_CARD + case CMD6: + RetVal |= RESP_R1 | XSDPS_DAT_PRESENT_SEL_MASK; + break; +#else + case CMD6: + RetVal |= RESP_R1B; + break; +#endif + + case ACMD6: + RetVal |= RESP_R1; + break; + case CMD7: + RetVal |= RESP_R1; + break; + +#ifndef MMC_CARD + case CMD8: + RetVal |= RESP_R1; + break; +#else + case CMD8: + RetVal |= RESP_R1 | XSDPS_DAT_PRESENT_SEL_MASK; + break; +#endif + + case CMD9: + RetVal |= RESP_R2; + break; + case CMD10: + case CMD12: + case ACMD13: + case CMD16: + RetVal |= RESP_R1; + break; + case CMD17: + case CMD18: + RetVal |= RESP_R1 | XSDPS_DAT_PRESENT_SEL_MASK; + break; + case CMD23: + case ACMD23: + case CMD24: + case CMD25: + RetVal |= RESP_R1 | XSDPS_DAT_PRESENT_SEL_MASK; + case ACMD41: + RetVal |= RESP_R3; + break; + case ACMD42: + RetVal |= RESP_R1; + break; + case ACMD51: + RetVal |= RESP_R1 | XSDPS_DAT_PRESENT_SEL_MASK; + break; + case CMD52: + case CMD55: + RetVal |= RESP_R1; + break; + case CMD58: + break; + } + + return RetVal; +} + +/*****************************************************************************/ +/** +* This function performs SD read in polled mode. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Arg is the address passed by the user that is to be sent as +* argument along with the command. +* @param BlkCnt - Block count passed by the user. +* @param Buff - Pointer to the data buffer for a DMA transfer. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because another transfer +* is in progress or command or data inhibit is set +* +******************************************************************************/ +int XSdPs_ReadPolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, u8 *Buff) +{ + u32 Status; + u32 PresentStateReg; + u32 StatusReg; + + if(InstancePtr->Config.CardDetect) { + /* + * Check status to ensure card is initialized + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0x0) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* + * Set block size to 512 if not already set + */ + if( XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET) != XSDPS_BLK_SIZE_512_MASK ) { + Status = XSdPs_SetBlkSize(InstancePtr, + XSDPS_BLK_SIZE_512_MASK); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, Buff); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_AUTO_CMD12_EN_MASK | + XSDPS_TM_BLK_CNT_EN_MASK | XSDPS_TM_DAT_DIR_SEL_MASK | + XSDPS_TM_DMA_EN_MASK | XSDPS_TM_MUL_SIN_BLK_SEL_MASK); + + Xil_DCacheInvalidateRange(Buff, BlkCnt * XSDPS_BLK_SIZE_512_MASK); + + /* + * Send block read command + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD18, Arg, BlkCnt); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + */ + do { + StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET); + if (StatusReg & XSDPS_INTR_ERR_MASK) { + /* + * Write to clear error bits + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + Status = XST_FAILURE; + goto RETURN_PATH; + } + } while((StatusReg & XSDPS_INTR_TC_MASK) == 0); + + /* + * Write to clear bit + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK); + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* This function performs SD write in polled mode. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Arg is the address passed by the user that is to be sent as +* argument along with the command. +* @param BlkCnt - Block count passed by the user. +* @param Buff - Pointer to the data buffer for a DMA transfer. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because another transfer +* is in progress or command or data inhibit is set +* +******************************************************************************/ +int XSdPs_WritePolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, const u8 *Buff) +{ + u32 Status; + u32 PresentStateReg; + u32 StatusReg; + + if(InstancePtr->Config.CardDetect) { + /* + * Check status to ensure card is initialized + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0x0) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* + * Set block size to 512 if not already set + */ + if( XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET) != XSDPS_BLK_SIZE_512_MASK ) { + Status = XSdPs_SetBlkSize(InstancePtr, + XSDPS_BLK_SIZE_512_MASK); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + } + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, Buff); + Xil_DCacheFlushRange(Buff, BlkCnt * XSDPS_BLK_SIZE_512_MASK); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_AUTO_CMD12_EN_MASK | + XSDPS_TM_BLK_CNT_EN_MASK | + XSDPS_TM_MUL_SIN_BLK_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + /* + * Send block write command + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD25, Arg, BlkCnt); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + * Polling for response for now + */ + do { + StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET); + if (StatusReg & XSDPS_INTR_ERR_MASK) { + /* + * Write to clear error bits + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + Status = XST_FAILURE; + goto RETURN_PATH; + } + } while((StatusReg & XSDPS_INTR_TC_MASK) == 0); + + /* + * Write to clear bit + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Selects card and sets default block size +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XSdPs_Select_Card (XSdPs *InstancePtr) +{ + u32 Status = 0; + + /* + * Send CMD7 - Select card + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD7, + InstancePtr->RelCardAddr, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + /* + * Set default block size + */ + Status = XSdPs_SetBlkSize(InstancePtr, XSDPS_BLK_SIZE_512_MASK); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to setup ADMA2 descriptor table +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param BlkCnt - block count. +* @param Buff pointer to data buffer. +* +* @return None +* +* @note None. +* +******************************************************************************/ +void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff) +{ + u32 TotalDescLines = 0; + u32 DescNum = 0; + u32 BlkSize = 0; + + /* + * Setup ADMA2 - Write descriptor table and point ADMA SAR to it + */ + BlkSize = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET); + BlkSize = BlkSize & XSDPS_BLK_SIZE_MASK; + + if((BlkCnt*BlkSize) < XSDPS_DESC_MAX_LENGTH) { + + TotalDescLines = 1; + + }else { + + TotalDescLines = ((BlkCnt*BlkSize) / XSDPS_DESC_MAX_LENGTH); + if ((BlkCnt * BlkSize) % XSDPS_DESC_MAX_LENGTH) + TotalDescLines += 1; + + } + + for (DescNum = 0; DescNum < (TotalDescLines-1); DescNum++) { + InstancePtr->Adma2_DescrTbl[DescNum].Address = + (u32)(Buff + (DescNum*XSDPS_DESC_MAX_LENGTH)); + InstancePtr->Adma2_DescrTbl[DescNum].Attribute = + XSDPS_DESC_TRAN | XSDPS_DESC_VALID; + /* + * This will write '0' to length field which indicates 65536 + */ + InstancePtr->Adma2_DescrTbl[DescNum].Length = + (u16)XSDPS_DESC_MAX_LENGTH; + } + + InstancePtr->Adma2_DescrTbl[TotalDescLines-1].Address = + (u32)(Buff + (DescNum*XSDPS_DESC_MAX_LENGTH)); + + InstancePtr->Adma2_DescrTbl[TotalDescLines-1].Attribute = + XSDPS_DESC_TRAN | XSDPS_DESC_END | XSDPS_DESC_VALID; + + InstancePtr->Adma2_DescrTbl[TotalDescLines-1].Length = + (BlkCnt*BlkSize) - (DescNum*XSDPS_DESC_MAX_LENGTH); + + + XSdPs_WriteReg(InstancePtr->Config.BaseAddress, XSDPS_ADMA_SAR_OFFSET, + (u32)&(InstancePtr->Adma2_DescrTbl[0])); + + Xil_DCacheFlushRange(&(InstancePtr->Adma2_DescrTbl[0]), + sizeof(XSdPs_Adma2Descriptor) * 32); + +} + +/*****************************************************************************/ +/** +* Mmc initialization is done in this function +* +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because +* a) MMC is already initialized +* b) There is no card inserted +* c) One of the steps (commands) in the initialization +* cycle failed +* @note This function initializes the SD card by following its +* initialization and identification state diagram. +* CMD0 is sent to reset card. +* CMD1 sent to identify voltage and high capacity support +* CMD2 and CMD3 are sent to obtain Card ID and +* Relative card address respectively. +* CMD9 is sent to read the card specific data. +* +******************************************************************************/ +int XSdPs_MmcCardInitialize(XSdPs *InstancePtr) +{ + u32 PresentStateReg; + u32 Status; + u32 RespOCR = 0x0; + u32 CSD[4]; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + if(InstancePtr->Config.CardDetect) { + /* + * Check the present state register to make sure + * card is inserted and detected by host controller + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* + * 74 CLK delay after card is powered up, before the first command. + */ + +#ifdef __arm__ + + usleep(XSDPS_INIT_DELAY); + +#endif + +#ifdef __MICROBLAZE__ + + /* 2 msec delay */ + MB_Sleep(2); + +#endif + + /* + * CMD0 no response expected + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD0, 0, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + InstancePtr->CardType = CT_MMC; + RespOCR = 0; + /* + * Send CMD1 while card is still busy with power up + */ + while ((RespOCR & XSDPS_RESPOCR_READY) == 0) { + + /* + * Host High Capacity support & High volage window + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD1, + XSDPS_ACMD41_HCS | XSDPS_CMD1_HIGH_VOL, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Response with card capacity + */ + RespOCR = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + } + + /* + * Update HCS support flag based on card capacity response + */ + if (RespOCR & XSDPS_ACMD41_HCS) + InstancePtr->HCS = 1; + + /* + * CMD2 for Card ID + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD2, 0, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + InstancePtr->CardID[0] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + InstancePtr->CardID[1] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP1_OFFSET); + InstancePtr->CardID[2] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP2_OFFSET); + InstancePtr->CardID[3] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP3_OFFSET); + + Status = XSdPs_CmdTransfer(InstancePtr, CMD3, 0, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Relative card address is stored as the upper 16 bits + * This is to avoid shifting when sending commands + */ + InstancePtr->RelCardAddr = + XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET) & 0xFFFF0000; + + Status = XSdPs_CmdTransfer(InstancePtr, CMD9, (InstancePtr->RelCardAddr), 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Card specific data is read. + * Currently not used for any operation. + */ + CSD[0] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + CSD[1] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP1_OFFSET); + CSD[2] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP2_OFFSET); + CSD[3] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP3_OFFSET); + + Status = XST_SUCCESS; + +RETURN_PATH: + return Status; + +} +/** @} */ diff --git a/XilinxProcessorIPLib/drivers/sdps/src/xsdps.h b/XilinxProcessorIPLib/drivers/sdps/src/xsdps.h new file mode 100644 index 00000000..51edffea --- /dev/null +++ b/XilinxProcessorIPLib/drivers/sdps/src/xsdps.h @@ -0,0 +1,212 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps.h +* @addtogroup sdps_v2_4 +* @{ +* @details +* +* This file contains the implementation of XSdPs driver. +* This driver is used initialize read from and write to the SD card. +* Features such as switching bus width to 4-bit and switching to high speed, +* changing clock frequency, block size etc. are supported. +* SD 2.0 uses 1/4 bus width and speeds of 25/50KHz. Initialization, however +* is done using 1-bit bus width and 400KHz clock frequency. +* SD commands are classified as broadcast and addressed. Commands can be +* those with response only (using only command line) or +* response + data (using command and data lines). +* Only one command can be sent at a time. During a data transfer however, +* when dsta lines are in use, certain commands (which use only the command +* line) can be sent, most often to obtain status. +* This driver does not support multi card slots at present. +* +* Intialization: +* This includes initialization on the host controller side to select +* clock frequency, bus power and default transfer related parameters. +* The default voltage is 3.3V. +* On the SD card side, the initialization and identification state diagram is +* implemented. This resets the card, gives it a unique address/ID and +* identifies key card related specifications. +* +* Data transfer: +* The SD card is put in tranfer state to read from or write to it. +* The default block size is 512 bytes and if supported, +* default bus width is 4-bit and bus speed is High speed. +* The read and write functions are implemented in polled mode using ADMA2. +* +* At any point, when key parameters such as block size or +* clock/speed or bus width are modified, this driver takes care of +* maintaining the same selection on host and card. +* All error bits in host controller are monitored by the driver and in the +* event one of them is set, driver will clear the interrupt status and +* communicate failure to the upper layer. +* +* File system use: +* This driver can be used with xilffs library to read and write files to SD. +* (Please refer to procedure in diskio.c). The file system read/write example +* in polled mode can used for reference. +* +* There is no example for using SD driver without file system at present. +* However, the driver can be used without the file system. The glue layer +* in filesytem can be used as reference for the same. The block count +* passed to the read/write function in one call is limited by the ADMA2 +* descriptor table and hence care will have to be taken to call read/write +* API's in a loop for large file sizes. +* +* Interrupt mode is not supported because it offers no improvement when used +* with file system. +* +* eMMC support: +* SD driver supports SD and eMMC based on the "enable MMC" parameter in SDK. +* The features of eMMC supported by the driver will depend on those supported +* by the host controller. The current driver supports read/write on eMMC card +* using 4-bit and high speed mode currently. +* +* Features not supported include - card write protect, password setting, +* lock/unlock, interrupts, SDMA mode, programmed I/O mode and +* 64-bit addressed ADMA2, erase/pre-erase commands. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.00a hk/sg 10/17/13 Initial release +* 2.0 hk 03/07/14 Version number revised. +* 2.1 hk 04/18/14 Increase sleep for eMMC switch command. +* Add sleep for microblaze designs. CR# 781117. +* 2.2 hk 07/28/14 Make changes to enable use of data cache. +* 2.3 sk 09/23/14 Send command for relative card address +* when re-initialization is done.CR# 819614. +* Use XSdPs_Change_ClkFreq API whenever changing +* clock.CR# 816586. +* 2.4 sk 12/04/14 Added support for micro SD without +* WP/CD. CR# 810655. +* Checked for DAT Inhibit mask instead of CMD +* Inhibit mask in Cmd Transfer API. +* Added Support for SD Card v1.0 +* +*+* +******************************************************************************/ + + +#ifndef SDPS_H_ +#define SDPS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xstatus.h" +#include "xsdps_hw.h" +#include
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.00a hk/sg 10/17/13 Initial release +* +*+* +******************************************************************************/ + + + +#include "xparameters.h" +#include "xsdps.h" + +/* +* The configuration table for devices +*/ + +XSdPs_Config XSdPs_ConfigTable[] = +{ + { + XPAR_XSDPS_0_DEVICE_ID, + XPAR_XSDPS_0_BASEADDR, + XPAR_XSDPS_0_SDIO_CLK_FREQ_HZ + } +}; +/** @} */ diff --git a/XilinxProcessorIPLib/drivers/sdps/src/xsdps_hw.h b/XilinxProcessorIPLib/drivers/sdps/src/xsdps_hw.h new file mode 100644 index 00000000..c974a3c0 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/sdps/src/xsdps_hw.h @@ -0,0 +1,609 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps_hw.h +* @addtogroup sdps_v2_4 +* @{ +* @details +* +* This header file contains the identifiers and basic HW access driver +* functions (or macros) that can be used to access the device. Other driver +* functions are defined in xsdps.h. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.00a hk/sg 10/17/13 Initial release +* +*+* +******************************************************************************/ + +#ifndef SD_HW_H_ +#define SD_HW_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" +#include "xparameters.h" + +/************************** Constant Definitions *****************************/ + +/** @name Register Map + * + * Register offsets from the base address of an SD device. + * @{ + */ + +#define XSDPS_SDMA_SYS_ADDR_OFFSET 0x00 /**< SDMA System Address + Register */ +#define XSDPS_BLK_SIZE_OFFSET 0x04 /**< Block Size Register */ +#define XSDPS_BLK_CNT_OFFSET 0x06 /**< Block Count Register */ +#define XSDPS_ARGMT_OFFSET 0x08 /**< Argument Register */ +#define XSDPS_XFER_MODE_OFFSET 0x0C /**< Transfer Mode Register */ +#define XSDPS_CMD_OFFSET 0x0E /**< Command Register */ +#define XSDPS_RESP0_OFFSET 0x10 /**< Response0 Register */ +#define XSDPS_RESP1_OFFSET 0x14 /**< Response1 Register */ +#define XSDPS_RESP2_OFFSET 0x18 /**< Response2 Register */ +#define XSDPS_RESP3_OFFSET 0x1C /**< Response3 Register */ +#define XSDPS_BUF_DAT_PORT_OFFSET 0x20 /**< Buffer Data Port */ +#define XSDPS_PRES_STATE_OFFSET 0x24 /**< Present State */ +#define XSDPS_HOST_CTRL1_OFFSET 0x28 /**< Host Control 1 */ +#define XSDPS_POWER_CTRL_OFFSET 0x29 /**< Power Control */ +#define XSDPS_BLK_GAP_CTRL_OFFSET 0x2A /**< Block Gap Control */ +#define XSDPS_WAKE_UP_CTRL_OFFSET 0x2B /**< Wake Up Control */ +#define XSDPS_CLK_CTRL_OFFSET 0x2C /**< Clock Control */ +#define XSDPS_TIMEOUT_CTRL_OFFSET 0x2E /**< Timeout Control */ +#define XSDPS_SW_RST_OFFSET 0x2F /**< Software Reset */ +#define XSDPS_NORM_INTR_STS_OFFSET 0x30 /**< Normal Interrupt + Status Register */ +#define XSDPS_ERR_INTR_STS_OFFSET 0x32 /**< Error Interrupt + Status Register */ +#define XSDPS_NORM_INTR_STS_EN_OFFSET 0x34 /**< Normal Interrupt + Status Enable Register */ +#define XSDPS_ERR_INTR_STS_EN_OFFSET 0x36 /**< Error Interrupt + Status Enable Register */ +#define XSDPS_NORM_INTR_SIG_EN_OFFSET 0x38 /**< Normal Interrupt + Signal Enable Register */ +#define XSDPS_ERR_INTR_SIG_EN_OFFSET 0x3A /**< Error Interrupt + Signal Enable Register */ + +#define XSDPS_AUTO_CMD12_ERR_STS_OFFSET 0x3C /**< Auto CMD12 Error Status + Register */ +#define XSDPS_HOST_CTRL2_OFFSET 0x3E /**< Host Control2 Register */ +#define XSDPS_CAPS_OFFSET 0x40 /**< Capabilities Register */ +#define XSDPS_CAPS_EXT_OFFSET 0x44 /**< Capabilities Extended */ +#define XSDPS_MAX_CURR_CAPS_OFFSET 0x48 /**< Maximum Current + Capabilities Register */ +#define XSDPS_MAX_CURR_CAPS_EXT_OFFSET 0x4C /**< Maximum Current + Capabilities Ext Register */ +#define XSDPS_FE_ERR_INT_STS_OFFSET 0x52 /**< Force Event for + Error Interrupt Status */ +#define XSDPS_FE_AUTO_CMD12_EIS_OFFSET 0x50 /**< Auto CM12 Error Interrupt + Status Register */ +#define XSDPS_ADMA_ERR_STS_OFFSET 0x54 /**< ADMA Error Status + Register */ +#define XSDPS_ADMA_SAR_OFFSET 0x58 /**< ADMA System Address + Register */ +#define XSDPS_ADMA_SAR_EXT_OFFSET 0x5C /**< ADMA System Address + Extended Register */ +#define XSDPS_PRE_VAL_1_OFFSET 0x60 /**< Preset Value Register */ +#define XSDPS_PRE_VAL_2_OFFSET 0x64 /**< Preset Value Register */ +#define XSDPS_PRE_VAL_3_OFFSET 0x68 /**< Preset Value Register */ +#define XSDPS_PRE_VAL_4_OFFSET 0x6C /**< Preset Value Register */ +#define XSDPS_SHARED_BUS_CTRL_OFFSET 0xE0 /**< Shared Bus Control + Register */ +#define XSDPS_SLOT_INTR_STS_OFFSET 0xFC /**< Slot Interrupt Status + Register */ +#define XSDPS_HOST_CTRL_VER_OFFSET 0xFE /**< Host Controller Version + Register */ + +/* @} */ + +/** @name Control Register - Host control, Power control, + * Block Gap control and Wakeup control + * + * This register contains bits for various configuration options of + * the SD host controller. Read/Write apart from the reserved bits. + * @{ + */ + +#define XSDPS_HC_LED_MASK 0x00000001 /**< LED Control */ +#define XSDPS_HC_WIDTH_MASK 0x00000002 /**< Bus width */ +#define XSDPS_HC_SPEED_MASK 0x00000004 /**< High Speed */ +#define XSDPS_HC_DMA_MASK 0x00000018 /**< DMA Mode Select */ +#define XSDPS_HC_DMA_SDMA_MASK 0x00000000 /**< SDMA Mode */ +#define XSDPS_HC_DMA_ADMA1_MASK 0x00000008 /**< ADMA1 Mode */ +#define XSDPS_HC_DMA_ADMA2_32_MASK 0x00000010 /**< ADMA2 Mode - 32 bit */ +#define XSDPS_HC_DMA_ADMA2_64_MASK 0x00000018 /**< ADMA2 Mode - 64 bit */ +#define XSDPS_HC_EXT_BUS_WIDTH 0x00000020 /**< Bus width - 8 bit */ +#define XSDPS_HC_CARD_DET_TL_MASK 0x00000040 /**< Card Detect Tst Lvl */ +#define XSDPS_HC_CARD_DET_SD_MASK 0x00000080 /**< Card Detect Sig Det */ + +#define XSDPS_PC_BUS_PWR_MASK 0x00000001 /**< Bus Power Control */ +#define XSDPS_PC_BUS_VSEL_MASK 0x0000000E /**< Bus Voltage Select */ +#define XSDPS_PC_BUS_VSEL_3V3_MASK 0x0000000E /**< Bus Voltage 3.3V */ +#define XSDPS_PC_BUS_VSEL_3V0_MASK 0x0000000C /**< Bus Voltage 3.0V */ +#define XSDPS_PC_BUS_VSEL_1V8_MASK 0x0000000A /**< Bus Voltage 1.8V */ + +#define XSDPS_BGC_STP_REQ_MASK 0x00000001 /**< Block Gap Stop Req */ +#define XSDPS_BGC_CNT_REQ_MASK 0x00000002 /**< Block Gap Cont Req */ +#define XSDPS_BGC_RWC_MASK 0x00000004 /**< Block Gap Rd Wait */ +#define XSDPS_BGC_INTR_MASK 0x00000008 /**< Block Gap Intr */ +#define XSDPS_BGC_SPI_MODE_MASK 0x00000010 /**< Block Gap SPI Mode */ +#define XSDPS_BGC_BOOT_EN_MASK 0x00000020 /**< Block Gap Boot Enb */ +#define XSDPS_BGC_ALT_BOOT_EN_MASK 0x00000040 /**< Block Gap Alt BootEn */ +#define XSDPS_BGC_BOOT_ACK_MASK 0x00000080 /**< Block Gap Boot Ack */ + +#define XSDPS_WC_WUP_ON_INTR_MASK 0x00000001 /**< Wakeup Card Intr */ +#define XSDPS_WC_WUP_ON_INSRT_MASK 0x00000002 /**< Wakeup Card Insert */ +#define XSDPS_WC_WUP_ON_REM_MASK 0x00000004 /**< Wakeup Card Removal */ + +/* @} */ + +/** @name Control Register - Clock control, Timeout control & Software reset + * + * This register contains bits for configuration options of clock, timeout and + * software reset. + * Read/Write except for Inter_Clock_Stable bit (read only) and reserved bits. + * @{ + */ + +#define XSDPS_CC_INT_CLK_EN_MASK 0x00000001 +#define XSDPS_CC_INT_CLK_STABLE_MASK 0x00000002 +#define XSDPS_CC_SD_CLK_EN_MASK 0x00000004 +#define XSDPS_CC_SD_CLK_GEN_SEL_MASK 0x00000020 +#define XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK 0x000000C0 +#define XSDPS_CC_SDCLK_FREQ_SEL_MASK 0x0000FF00 +#define XSDPS_CC_SDCLK_FREQ_D256_MASK 0x00008000 +#define XSDPS_CC_SDCLK_FREQ_D128_MASK 0x00004000 +#define XSDPS_CC_SDCLK_FREQ_D64_MASK 0x00002000 +#define XSDPS_CC_SDCLK_FREQ_D32_MASK 0x00001000 +#define XSDPS_CC_SDCLK_FREQ_D16_MASK 0x00000800 +#define XSDPS_CC_SDCLK_FREQ_D8_MASK 0x00000400 +#define XSDPS_CC_SDCLK_FREQ_D4_MASK 0x00000200 +#define XSDPS_CC_SDCLK_FREQ_D2_MASK 0x00000100 +#define XSDPS_CC_SDCLK_FREQ_BASE_MASK 0x00000000 + +#define XSDPS_TC_CNTR_VAL_MASK 0x0000000F + +#define XSDPS_SWRST_ALL_MASK 0x00000001 +#define XSDPS_SWRST_CMD_LINE_MASK 0x00000002 +#define XSDPS_SWRST_DAT_LINE_MASK 0x00000004 + +#define XSDPS_CC_MAX_NUM_OF_DIV 9 +#define XSDPS_CC_DIV_SHIFT 8 + +/* @} */ + +/** @name SD Interrupt Registers + * + * Normal and Error Interrupt Status Register + * This register shows the normal and error interrupt status. + * Status enable register affects reads of this register. + * If Signal enable register is set and the corresponding status bit is set, + * interrupt is generated. + * Write to clear except + * Error_interrupt and Card_Interrupt bits - Read only + * + * Normal and Error Interrupt Status Enable Register + * Setting this register bits enables Interrupt status. + * Read/Write except Fixed_to_0 bit (Read only) + * + * Normal and Error Interrupt Signal Enable Register + * This register is used to select which interrupt status is + * indicated to the Host System as the interrupt. + * Read/Write except Fixed_to_0 bit (Read only) + * + * All three registers have same bit definitions + * @{ + */ + +#define XSDPS_INTR_CC_MASK 0x00000001 /**< Command Complete */ +#define XSDPS_INTR_TC_MASK 0x00000002 /**< Transfer Complete */ +#define XSDPS_INTR_BGE_MASK 0x00000004 /**< Block Gap Event */ +#define XSDPS_INTR_DMA_MASK 0x00000008 /**< DMA Interrupt */ +#define XSDPS_INTR_BWR_MASK 0x00000010 /**< Buffer Write Ready */ +#define XSDPS_INTR_BRR_MASK 0x00000020 /**< Buffer Read Ready */ +#define XSDPS_INTR_CARD_INSRT_MASK 0x00000040 /**< Card Insert */ +#define XSDPS_INTR_CARD_REM_MASK 0x00000080 /**< Card Remove */ +#define XSDPS_INTR_CARD_MASK 0x00000100 /**< Card Interrupt */ +#define XSDPS_INTR_INT_A_MASK 0x00000200 /**< INT A Interrupt */ +#define XSDPS_INTR_INT_B_MASK 0x00000400 /**< INT B Interrupt */ +#define XSDPS_INTR_INT_C_MASK 0x00000800 /**< INT C Interrupt */ +#define XSDPS_INTR_RE_TUNING_MASK 0x00001000 /**< Re-Tuning Interrupt */ +#define XSDPS_INTR_BOOT_TERM_MASK 0x00002000 /**< Boot Terminate + Interrupt */ +#define XSDPS_INTR_BOOT_ACK_RECV_MASK 0x00004000 /**< Boot Ack Recv + Interrupt */ +#define XSDPS_INTR_ERR_MASK 0x00008000 /**< Error Interrupt */ +#define XSDPS_NORM_INTR_ALL_MASK 0x0000FFFF + +#define XSDPS_INTR_ERR_CT_MASK 0x00000001 /**< Command Timeout + Error */ +#define XSDPS_INTR_ERR_CCRC_MASK 0x00000002 /**< Command CRC Error */ +#define XSDPS_INTR_ERR_CEB_MASK 0x00000004 /**< Command End Bit + Error */ +#define XSDPS_INTR_ERR_CI_MASK 0x00000008 /**< Command Index Error */ +#define XSDPS_INTR_ERR_DT_MASK 0x00000010 /**< Data Timeout Error */ +#define XSDPS_INTR_ERR_DCRC_MASK 0x00000020 /**< Data CRC Error */ +#define XSDPS_INTR_ERR_DEB_MASK 0x00000040 /**< Data End Bit Error */ +#define XSDPS_INTR_ERR_I_LMT_MASK 0x00000080 /**< Current Limit Error */ +#define XSDPS_INTR_ERR_AUTO_CMD12_MASK 0x00000100 /**< Auto CMD12 Error */ +#define XSDPS_INTR_ERR_ADMA_MASK 0x00000200 /**< ADMA Error */ +#define XSDPS_INTR_ERR_TR_MASK 0x00001000 /**< Tuning Error */ +#define XSDPS_INTR_VEND_SPF_ERR_MASK 0x0000E000 /**< Vendor Specific + Error */ +#define XSDPS_ERROR_INTR_ALL_MASK 0x0000F3FF /**< Mask for error bits */ +/* @} */ + +/** @name Block Size and Block Count Register + * + * This register contains the block count for current transfer, + * block size and SDMA buffer size. + * Read/Write except for reserved bits. + * @{ + */ + +#define XSDPS_BLK_SIZE_MASK 0x00000FFF /**< Transfer Block Size */ +#define XSDPS_SDMA_BUFF_SIZE_MASK 0x00007000 /**< Host SDMA Buffer Size */ +#define XSDPS_BLK_CNT_MASK 0x0000FFFF /**< Block Count for + Current Transfer */ + +/* @} */ + +/** @name Transfer Mode and Command Register + * + * The Transfer Mode register is used to control the data transfers and + * Command register is used for command generation + * Read/Write except for reserved bits. + * @{ + */ + +#define XSDPS_TM_DMA_EN_MASK 0x00000001 /**< DMA Enable */ +#define XSDPS_TM_BLK_CNT_EN_MASK 0x00000002 /**< Block Count Enable */ +#define XSDPS_TM_AUTO_CMD12_EN_MASK 0x00000004 /**< Auto CMD12 Enable */ +#define XSDPS_TM_DAT_DIR_SEL_MASK 0x00000010 /**< Data Transfer + Direction Select */ +#define XSDPS_TM_MUL_SIN_BLK_SEL_MASK 0x00000020 /**< Multi/Single + Block Select */ + +#define XSDPS_CMD_RESP_SEL_MASK 0x00000003 /**< Response Type + Select */ +#define XSDPS_CMD_RESP_NONE_MASK 0x00000000 /**< No Response */ +#define XSDPS_CMD_RESP_L136_MASK 0x00000001 /**< Response length 138 */ +#define XSDPS_CMD_RESP_L48_MASK 0x00000002 /**< Response length 48 */ +#define XSDPS_CMD_RESP_L48_BSY_CHK_MASK 0x00000003 /**< Response length 48 & + check busy after + response */ +#define XSDPS_CMD_CRC_CHK_EN_MASK 0x00000008 /**< Command CRC Check + Enable */ +#define XSDPS_CMD_INX_CHK_EN_MASK 0x00000010 /**< Command Index Check + Enable */ +#define XSDPS_DAT_PRESENT_SEL_MASK 0x00000020 /**< Data Present Select */ +#define XSDPS_CMD_TYPE_MASK 0x000000C0 /**< Command Type */ +#define XSDPS_CMD_TYPE_NORM_MASK 0x00000000 /**< CMD Type - Normal */ +#define XSDPS_CMD_TYPE_SUSPEND_MASK 0x00000040 /**< CMD Type - Suspend */ +#define XSDPS_CMD_TYPE_RESUME_MASK 0x00000080 /**< CMD Type - Resume */ +#define XSDPS_CMD_TYPE_ABORT_MASK 0x000000C0 /**< CMD Type - Abort */ +#define XSDPS_CMD_MASK 0x00003F00 /**< Command Index Mask - + Set to CMD0-63, + AMCD0-63 */ + +/* @} */ + +/** @name Capabilities Register + * + * Capabilities register is a read only register which contains + * information about the host controller. + * Sufficient if read once after power on. + * Read Only + * @{ + */ +#define XSDPS_CAP_TOUT_CLK_FREQ_MASK 0x0000003F /**< Timeout clock freq + select */ +#define XSDPS_CAP_TOUT_CLK_UNIT_MASK 0x00000080 /**< Timeout clock unit - + MHz/KHz */ +#define XSDPS_CAP_MAX_BLK_LEN_MASK 0x00030000 /**< Max block length */ +#define XSDPS_CAP_MAX_BLK_LEN_512B_MASK 0x00000000 /**< Max block 512 bytes */ +#define XSDPS_CAP_EXT_MEDIA_BUS_MASK 0x00040000 /**< Extended media bus */ +#define XSDPS_CAP_ADMA2_MASK 0x00080000 /**< ADMA2 support */ +#define XSDPS_CAP_HIGH_SPEED_MASK 0x00200000 /**< High speed support */ +#define XSDPS_CAP_SDMA_MASK 0x00400000 /**< SDMA support */ +#define XSDPS_CAP_SUSP_RESUME_MASK 0x00800000 /**< Suspend/Resume + support */ +#define XSDPS_CAP_VOLT_3V3_MASK 0x01000000 /**< 3.3V support */ +#define XSDPS_CAP_VOLT_3V0_MASK 0x02000000 /**< 3.0V support */ +#define XSDPS_CAP_VOLT_1V8_MASK 0x04000000 /**< 1.8V support */ +#define XSDPS_CAP_INTR_MODE_MASK 0x08000000 /**< Interrupt mode + support */ +#define XSDPS_CAP_SYS_BUS_64_MASK 0x10000000 /**< 64 bit system bus + support */ +#define XSDPS_CAP_SPI_MODE_MASK 0x20000000 /**< SPI mode */ +#define XSDPS_CAP_SPI_BLOCK_MODE_MASK 0x20000000 /**< SPI block mode */ +/* @} */ + +/** @name Present State Register + * + * Gives the current status of the host controller + * Read Only + * @{ + */ + +#define XSDPS_PSR_INHIBIT_CMD_MASK 0x00000001 /**< Command inhibit - CMD */ +#define XSDPS_PSR_INHIBIT_DAT_MASK 0x00000002 /**< Command Inhibit - DAT */ +#define XSDPS_PSR_DAT_ACTIVE_MASK 0x00000004 /**< DAT line active */ +#define XSDPS_PSR_WR_ACTIVE_MASK 0x00000100 /**< Write transfer active */ +#define XSDPS_PSR_RD_ACTIVE_MASK 0x00000200 /**< Read transfer active */ +#define XSDPS_PSR_BUFF_WR_EN_MASK 0x00000400 /**< Buffer write enable */ +#define XSDPS_PSR_BUFF_RD_EN_MASK 0x00000800 /**< Buffer read enable */ +#define XSDPS_PSR_CARD_INSRT_MASK 0x00010000 /**< Card inserted */ +#define XSDPS_PSR_CARD_STABLE_MASK 0x00020000 /**< Card state stable */ +#define XSDPS_PSR_CARD_DPL_MASK 0x00040000 /**< Card detect pin level */ +#define XSDPS_PSR_WPS_PL_MASK 0x00080000 /**< Write protect switch + pin level */ + +/* @} */ + +/** @name Block size mask for 512 bytes + * + * Block size mask for 512 bytes - This is the default block size. + * @{ + */ + +#define XSDPS_BLK_SIZE_512_MASK 0x200 + +/* @} */ + +/** @name Commands + * + * Constant definitions for commands and response related to SD + * @{ + */ + +#define XSDPS_APP_CMD_PREFIX 0x8000 +#define CMD0 0x0000 +#define CMD1 0x0100 +#define CMD2 0x0200 +#define CMD3 0x0300 +#define CMD4 0x0400 +#define CMD5 0x0500 +#define CMD6 0x0600 +#define ACMD6 (XSDPS_APP_CMD_PREFIX + 0x0600) +#define CMD7 0x0700 +#define CMD8 0x0800 +#define CMD9 0x0900 +#define CMD10 0x0A00 +#define CMD12 0x0C00 +#define ACMD13 (XSDPS_APP_CMD_PREFIX + 0x0D00) +#define CMD16 0x1000 +#define CMD17 0x1100 +#define CMD18 0x1200 +#define CMD23 0x1700 +#define ACMD23 (XSDPS_APP_CMD_PREFIX + 0x1700) +#define CMD24 0x1800 +#define CMD25 0x1900 +#define CMD41 0x2900 +#define ACMD41 (XSDPS_APP_CMD_PREFIX + 0x2900) +#define ACMD42 (XSDPS_APP_CMD_PREFIX + 0x2A00) +#define ACMD51 (XSDPS_APP_CMD_PREFIX + 0x3300) +#define CMD52 0x3400 +#define CMD55 0x3700 +#define CMD58 0x3A00 + +#define RESP_NONE XSDPS_CMD_RESP_NONE_MASK +#define RESP_R1 XSDPS_CMD_RESP_L48_MASK | XSDPS_CMD_CRC_CHK_EN_MASK | \ + XSDPS_CMD_INX_CHK_EN_MASK + +#define RESP_R1B XSDPS_CMD_RESP_L48_BSY_CHK_MASK | \ + XSDPS_CMD_CRC_CHK_EN_MASK | XSDPS_CMD_INX_CHK_EN_MASK + +#define RESP_R2 XSDPS_CMD_RESP_L136_MASK | XSDPS_CMD_CRC_CHK_EN_MASK +#define RESP_R3 XSDPS_CMD_RESP_L48_MASK + +#define RESP_R6 XSDPS_CMD_RESP_L48_BSY_CHK_MASK | \ + XSDPS_CMD_CRC_CHK_EN_MASK | XSDPS_CMD_INX_CHK_EN_MASK + +/* @} */ + +/** @name ADMA2 Descriptor related definitions + * + * ADMA2 Descriptor related definitions + * @{ + */ + +#define XSDPS_DESC_MAX_LENGTH 65536 + +#define XSDPS_DESC_VALID (0x1 << 0) +#define XSDPS_DESC_END (0x1 << 1) +#define XSDPS_DESC_INT (0x1 << 2) +#define XSDPS_DESC_TRAN (0x2 << 4) + +/* @} */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define XSdPs_In32 Xil_In32 +#define XSdPs_Out32 Xil_Out32 + +#define XSdPs_In16 Xil_In16 +#define XSdPs_Out16 Xil_Out16 + +#define XSdPs_In8 Xil_In8 +#define XSdPs_Out8 Xil_Out8 + +/****************************************************************************/ +/** +* Read a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to the target register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u32 XSdPs_ReadReg(u32 BaseAddress. int RegOffset) +* +******************************************************************************/ +#define XSdPs_ReadReg(BaseAddress, RegOffset) \ + XSdPs_In32((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* Write to a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to target register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(u32 BaseAddress, int RegOffset, +* u32 RegisterValue) +* +******************************************************************************/ +#define XSdPs_WriteReg(BaseAddress, RegOffset, RegisterValue) \ + XSdPs_Out32((BaseAddress) + (RegOffset), (RegisterValue)) + +/****************************************************************************/ +/** +* Read a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to the target register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u16 XSdPs_ReadReg(u32 BaseAddress. int RegOffset) +* +******************************************************************************/ +#define XSdPs_ReadReg16(BaseAddress, RegOffset) \ + XSdPs_In16((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* Write to a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to target register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(u32 BaseAddress, int RegOffset, +* u16 RegisterValue) +* +******************************************************************************/ +#define XSdPs_WriteReg16(BaseAddress, RegOffset, RegisterValue) \ + XSdPs_Out16((BaseAddress) + (RegOffset), (RegisterValue)) + +/****************************************************************************/ +/** +* Read a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to the target register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u8 XSdPs_ReadReg(u32 BaseAddress. int RegOffset) +* +******************************************************************************/ +#define XSdPs_ReadReg8(BaseAddress, RegOffset) \ + XSdPs_In8((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* Write to a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to target register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(u32 BaseAddress, int RegOffset, +* u8 RegisterValue) +* +******************************************************************************/ +#define XSdPs_WriteReg8(BaseAddress, RegOffset, RegisterValue) \ + XSdPs_Out8((BaseAddress) + (RegOffset), (RegisterValue)) + +/***************************************************************************/ +/** +* Macro to get present status register +* +* @param BaseAddress contains the base address of the device. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(u32 BaseAddress, int RegOffset, +* u8 RegisterValue) +* +******************************************************************************/ +#define XSdPs_GetPresentStatusReg(BaseAddress) \ + XSdPs_In32((BaseAddress) + (XSDPS_PRES_STATE_OFFSET)) + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SD_HW_H_ */ +/** @} */ diff --git a/XilinxProcessorIPLib/drivers/sdps/src/xsdps_options.c b/XilinxProcessorIPLib/drivers/sdps/src/xsdps_options.c new file mode 100644 index 00000000..179b73c1 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/sdps/src/xsdps_options.c @@ -0,0 +1,796 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps_options.c +* @addtogroup sdps_v2_4 +* @{ +* @details +* +* Contains API's for changing the various options in host and card. +* See xsdps.h for a detailed description of the device and driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.00a hk/sg 10/17/13 Initial release +* 2.1 hk 04/18/14 Increase sleep for eMMC switch command. +* Add sleep for microblaze designs. CR# 781117. +* 2.3 sk 09/23/14 Use XSdPs_Change_ClkFreq API whenever changing +* clock.CR# 816586. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xsdps.h" +/* + * The header sleep.h and API usleep() can only be used with an arm design. + * MB_Sleep() is used for microblaze design. + */ +#ifdef __arm__ + +#include "sleep.h" + +#endif + +#ifdef __MICROBLAZE__ + +#include "microblaze_sleep.h" + +#endif + +/************************** Constant Definitions *****************************/ +#define XSDPS_SCR_BLKCNT 1 +#define XSDPS_SCR_BLKSIZE 8 +#define XSDPS_4_BIT_WIDTH 0x2 +#define XSDPS_SWITCH_CMD_BLKCNT 1 +#define XSDPS_SWITCH_CMD_BLKSIZE 64 +#define XSDPS_SWITCH_CMD_HS_GET 0x00FFFFF0 +#define XSDPS_SWITCH_CMD_HS_SET 0x80FFFFF1 +#define XSDPS_EXT_CSD_CMD_BLKCNT 1 +#define XSDPS_EXT_CSD_CMD_BLKSIZE 512 +#define XSDPS_CLK_52_MHZ 52000000 +#define XSDPS_MMC_HIGH_SPEED_ARG 0x03B90100 +#define XSDPS_MMC_4_BIT_BUS_ARG 0x03B70100 +#define XSDPS_MMC_DELAY_FOR_SWITCH 2000 + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +int XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt); +void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff); + +/*****************************************************************************/ +/** +* Update Block size for read/write operations. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param BlkSize - Block size passed by the user. +* +* @return None +* +******************************************************************************/ +int XSdPs_SetBlkSize(XSdPs *InstancePtr, u16 BlkSize) +{ + u32 Status = 0; + u32 PresentStateReg = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + + if (PresentStateReg & (XSDPS_PSR_INHIBIT_CMD_MASK | + XSDPS_PSR_INHIBIT_DAT_MASK | + XSDPS_PSR_WR_ACTIVE_MASK | XSDPS_PSR_RD_ACTIVE_MASK)) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + + /* + * Send block write command + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD16, BlkSize, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + /* + * Set block size to the value passed + */ + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET, + BlkSize); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to get bus width support by card. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param SCR - buffer to store SCR register returned by card. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XSdPs_Get_BusWidth(XSdPs *InstancePtr, u8 *SCR) +{ + u32 Status = 0; + u32 StatusReg = 0x0; + u16 BlkCnt; + u16 BlkSize; + int LoopCnt; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (LoopCnt = 0; LoopCnt < 8; LoopCnt++) { + SCR[LoopCnt] = 0; + } + + /* + * Send block write command + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD55, + InstancePtr->RelCardAddr, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + BlkCnt = XSDPS_SCR_BLKCNT; + BlkSize = XSDPS_SCR_BLKSIZE; + + /* + * Set block size to the value passed + */ + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, SCR); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + Xil_DCacheInvalidateRange(SCR, 8); + + Status = XSdPs_CmdTransfer(InstancePtr, ACMD51, 0, BlkCnt); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + * Polling for response for now + */ + do { + StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET); + if (StatusReg & XSDPS_INTR_ERR_MASK) { + /* + * Write to clear error bits + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + Status = XST_FAILURE; + goto RETURN_PATH; + } + } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0); + + /* + * Write to clear bit + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK); + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to set bus width to 4-bit in card and host +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XSdPs_Change_BusWidth(XSdPs *InstancePtr) +{ + u32 Status = 0; + u32 StatusReg = 0x0; + u32 Arg = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + +#ifndef MMC_CARD + + Status = XSdPs_CmdTransfer(InstancePtr, CMD55, + InstancePtr->RelCardAddr, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Arg = XSDPS_4_BIT_WIDTH; + Status = XSdPs_CmdTransfer(InstancePtr, ACMD6, Arg, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET); + StatusReg |= XSDPS_HC_WIDTH_MASK; + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET,StatusReg); + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + +#else + + Arg = XSDPS_MMC_4_BIT_BUS_ARG; + Status = XSdPs_CmdTransfer(InstancePtr, ACMD6, Arg, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + +#ifdef __arm__ + + usleep(XSDPS_MMC_DELAY_FOR_SWITCH); + +#endif + +#ifdef __MICROBLAZE__ + + /* 2 msec delay */ + MB_Sleep(2); + +#endif + + StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET); + StatusReg |= XSDPS_HC_WIDTH_MASK; + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET,StatusReg); + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + +#endif + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to get bus speed supported by card. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param ReadBuff - buffer to store function group support data +* returned by card. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XSdPs_Get_BusSpeed(XSdPs *InstancePtr, u8 *ReadBuff) +{ + u32 Status = 0; + u32 StatusReg = 0x0; + u32 Arg = 0; + u16 BlkCnt; + u16 BlkSize; + int LoopCnt; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (LoopCnt = 0; LoopCnt < 64; LoopCnt++) { + ReadBuff[LoopCnt] = 0; + } + + BlkCnt = XSDPS_SWITCH_CMD_BLKCNT; + BlkSize = XSDPS_SWITCH_CMD_BLKSIZE; + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + Arg = XSDPS_SWITCH_CMD_HS_GET; + + Xil_DCacheInvalidateRange(ReadBuff, 64); + + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + * Polling for response for now + */ + do { + StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET); + if (StatusReg & XSDPS_INTR_ERR_MASK) { + /* + * Write to clear error bits + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + Status = XST_FAILURE; + goto RETURN_PATH; + } + } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0); + + /* + * Write to clear bit + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK); + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to set high speed in card and host. Changes clock in host accordingly. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XSdPs_Change_BusSpeed(XSdPs *InstancePtr) +{ + u32 Status = 0; + u32 StatusReg = 0x0; + u32 Arg = 0; + +#ifndef MMC_CARD + u32 ClockReg; + u8 ReadBuff[64]; + u16 BlkCnt; + u16 BlkSize; +#endif + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + +#ifndef MMC_CARD + + BlkCnt = XSDPS_SWITCH_CMD_BLKCNT; + BlkSize = XSDPS_SWITCH_CMD_BLKSIZE; + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff); + + Xil_DCacheInvalidateRange(ReadBuff, 64); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + Arg = XSDPS_SWITCH_CMD_HS_SET; + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + * Polling for response for now + */ + do { + StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET); + if (StatusReg & XSDPS_INTR_ERR_MASK) { + /* + * Write to clear error bits + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + Status = XST_FAILURE; + goto RETURN_PATH; + } + } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0); + + /* + * Write to clear bit + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK); + + /* + * Change the clock frequency to 50 MHz + */ + Status = XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_50_MHZ); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET); + StatusReg |= XSDPS_HC_SPEED_MASK; + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET,StatusReg); + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + +#else + + Arg = XSDPS_MMC_HIGH_SPEED_ARG; + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + +#ifdef __arm__ + + usleep(XSDPS_MMC_DELAY_FOR_SWITCH); + +#endif + +#ifdef __MICROBLAZE__ + + /* 2 msec delay */ + MB_Sleep(2); + +#endif + + XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_52_MHZ); + + StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET); + StatusReg |= XSDPS_HC_SPEED_MASK; + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET,StatusReg); + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); +#endif + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to change clock freq to given value. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param SelFreq - Clock frequency in Hz. +* +* @return None +* +* @note This API will change clock frequency to the value less than +* or equal to the given value using the permissible dividors. +* +******************************************************************************/ +int XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq) +{ + u16 ClockReg; + int DivCnt; + u16 Divisor; + u16 ClkLoopCnt; + int Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Disable clock + */ + ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + ClockReg &= ~(XSDPS_CC_INT_CLK_EN_MASK | XSDPS_CC_SD_CLK_EN_MASK); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET, ClockReg); + + /* + * Calculate divisor + */ + DivCnt = 0x1; + for(ClkLoopCnt = 0; ClkLoopCnt < XSDPS_CC_MAX_NUM_OF_DIV; + ClkLoopCnt++) { + if( ((InstancePtr->Config.InputClockHz)/DivCnt) <= SelFreq) { + Divisor = DivCnt/2; + Divisor = Divisor << XSDPS_CC_DIV_SHIFT; + break; + } + DivCnt = DivCnt << 1; + } + + if(ClkLoopCnt == 9) { + + /* + * No valid divisor found for given frequency + */ + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Set clock divisor + */ + ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + ClockReg &= (~XSDPS_CC_SDCLK_FREQ_SEL_MASK); + + ClockReg |= Divisor | XSDPS_CC_INT_CLK_EN_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET, ClockReg); + + /* + * Wait for internal clock to stabilize + */ + while((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET) & XSDPS_CC_INT_CLK_STABLE_MASK) == 0); + + /* + * Enable SD clock + */ + ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET, + ClockReg | XSDPS_CC_SD_CLK_EN_MASK); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to send pullup command to card before using DAT line 3(using 4-bit bus) +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XSdPs_Pullup(XSdPs *InstancePtr) +{ + u32 Status = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Status = XSdPs_CmdTransfer(InstancePtr, CMD55, + InstancePtr->RelCardAddr, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_CmdTransfer(InstancePtr, ACMD42, 0, 0); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to get EXT_CSD register of eMMC. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param ReadBuff - buffer to store EXT_CSD +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +int XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff) +{ + u32 Status = 0; + u32 StatusReg = 0x0; + u32 Arg = 0; + u16 BlkCnt; + u16 BlkSize; + int LoopCnt; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (LoopCnt = 0; LoopCnt < 512; LoopCnt++) { + ReadBuff[LoopCnt] = 0; + } + + BlkCnt = XSDPS_EXT_CSD_CMD_BLKCNT; + BlkSize = XSDPS_EXT_CSD_CMD_BLKSIZE; + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff); + + Xil_DCacheInvalidateRange(ReadBuff, 512); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + Arg = 0; + + /* + * Send SEND_EXT_CSD command + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD8, Arg, 1); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + * Polling for response for now + */ + do { + StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET); + if (StatusReg & XSDPS_INTR_ERR_MASK) { + /* + * Write to clear error bits + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + Status = XST_FAILURE; + goto RETURN_PATH; + } + } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0); + + /* + * Write to clear bit + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK); + + Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} +/** @} */ diff --git a/XilinxProcessorIPLib/drivers/sdps/src/xsdps_sinit.c b/XilinxProcessorIPLib/drivers/sdps/src/xsdps_sinit.c new file mode 100644 index 00000000..f8cffb46 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/sdps/src/xsdps_sinit.c @@ -0,0 +1,99 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps_sinit.c +* @addtogroup sdps_v2_4 +* @{ +* @details +* +* The implementation of the XSdPs component's static initialization +* functionality. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.00a hk/sg 10/17/13 Initial release +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xstatus.h" +#include "xsdps.h" +#include "xparameters.h" +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ +extern XSdPs_Config XSdPs_ConfigTable[]; + +/*****************************************************************************/ +/** +* +* Looks up the device configuration based on the unique device ID. A table +* contains the configuration info for each device in the system. +* +* @param DeviceId contains the ID of the device to look up the +* configuration for. +* +* @return +* +* A pointer to the configuration found or NULL if the specified device ID was +* not found. See xsdps.h for the definition of XSdPs_Config. +* +* @note None. +* +******************************************************************************/ +XSdPs_Config *XSdPs_LookupConfig(u16 DeviceId) +{ + XSdPs_Config *CfgPtr = NULL; + int Index; + + for (Index = 0; Index < XPAR_XSDPS_NUM_INSTANCES; Index++) { + if (XSdPs_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XSdPs_ConfigTable[Index]; + break; + } + } + return CfgPtr; +} +/** @} */