|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved.
|
|
|
|
|
* Copyright (C) 2013 - 2016 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
|
|
|
|
@ -55,6 +55,14 @@
|
|
|
|
|
* of SDR50, SDR104 and HS200.
|
|
|
|
|
* sk 02/16/16 Corrected the Tuning logic.
|
|
|
|
|
* sk 03/02/16 Configured the Tap Delay values for eMMC HS200 mode.
|
|
|
|
|
* 2.8 sk 04/20/16 Added new workaround for auto tuning.
|
|
|
|
|
* 3.0 sk 07/07/16 Used usleep API for both arm and microblaze.
|
|
|
|
|
* sk 07/16/16 Added support for UHS modes.
|
|
|
|
|
* sk 07/16/16 Added Tap delays accordingly to different SD/eMMC
|
|
|
|
|
* operating modes.
|
|
|
|
|
* 3.1 mi 09/07/16 Removed compilation warnings with extra compiler flags.
|
|
|
|
|
* sk 11/07/16 Enable Rst_n bit in ext_csd reg if not enabled.
|
|
|
|
|
* sk 11/16/16 Issue DLL reset at 31 iteration to load new zero value.
|
|
|
|
|
*
|
|
|
|
|
* </pre>
|
|
|
|
|
*
|
|
|
|
@ -62,24 +70,14 @@
|
|
|
|
|
|
|
|
|
|
/***************************** 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.
|
|
|
|
|
*/
|
|
|
|
|
#if defined (__arm__) || defined (__aarch64__)
|
|
|
|
|
|
|
|
|
|
#include "sleep.h"
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef __MICROBLAZE__
|
|
|
|
|
|
|
|
|
|
#include "microblaze_sleep.h"
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/************************** Constant Definitions *****************************/
|
|
|
|
|
|
|
|
|
|
#define UHS_SDR12_SUPPORT 0x1U
|
|
|
|
|
#define UHS_SDR25_SUPPORT 0x2U
|
|
|
|
|
#define UHS_SDR50_SUPPORT 0x4U
|
|
|
|
|
#define UHS_SDR104_SUPPORT 0x8U
|
|
|
|
|
#define UHS_DDR50_SUPPORT 0x10U
|
|
|
|
|
/**************************** Type Definitions *******************************/
|
|
|
|
|
|
|
|
|
|
/***************** Macros (Inline Functions) Definitions *********************/
|
|
|
|
@ -87,11 +85,13 @@
|
|
|
|
|
/************************** Function Prototypes ******************************/
|
|
|
|
|
s32 XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt);
|
|
|
|
|
void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff);
|
|
|
|
|
s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode);
|
|
|
|
|
static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr);
|
|
|
|
|
#if defined (ARMR5) || defined (__aarch64__)
|
|
|
|
|
s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode);
|
|
|
|
|
#if defined (__arm__) || defined (__aarch64__)
|
|
|
|
|
static void XSdPs_sdr50_tapdelay(u32 Bank, u32 DeviceId, u32 CardType);
|
|
|
|
|
static void XSdPs_ddr50_tapdelay(u32 Bank, u32 DeviceId, u32 CardType);
|
|
|
|
|
void XSdPs_SetTapDelay(XSdPs *InstancePtr);
|
|
|
|
|
static void XSdPs_DllReset(XSdPs *InstancePtr);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
@ -320,19 +320,8 @@ s32 XSdPs_Change_BusWidth(XSdPs *InstancePtr)
|
|
|
|
|
XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined (__arm__) || defined (__aarch64__)
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
@ -463,7 +452,6 @@ s32 XSdPs_Change_BusSpeed(XSdPs *InstancePtr)
|
|
|
|
|
s32 Status;
|
|
|
|
|
u32 StatusReg;
|
|
|
|
|
u32 Arg;
|
|
|
|
|
u32 ClockReg;
|
|
|
|
|
u16 BlkCnt;
|
|
|
|
|
u16 BlkSize;
|
|
|
|
|
u8 ReadBuff[64];
|
|
|
|
@ -610,25 +598,10 @@ s32 XSdPs_Change_BusSpeed(XSdPs *InstancePtr)
|
|
|
|
|
Status = XST_FAILURE;
|
|
|
|
|
goto RETURN_PATH;
|
|
|
|
|
}
|
|
|
|
|
#if defined (__arm__) || defined (__aarch64__)
|
|
|
|
|
/* Program the Tap delays */
|
|
|
|
|
XSdPs_SetTapDelay(InstancePtr);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined (__arm__) || defined (__aarch64__)
|
|
|
|
|
|
|
|
|
|
usleep(XSDPS_MMC_DELAY_FOR_SWITCH);
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef __MICROBLAZE__
|
|
|
|
|
|
|
|
|
|
/* 2 msec delay */
|
|
|
|
|
MB_Sleep(2);
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
StatusReg = (s32)XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_HOST_CTRL1_OFFSET);
|
|
|
|
|
StatusReg |= XSDPS_HC_SPEED_MASK;
|
|
|
|
@ -667,7 +640,6 @@ s32 XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq)
|
|
|
|
|
u16 DivCnt;
|
|
|
|
|
u16 Divisor = 0U;
|
|
|
|
|
u16 ExtDivisor;
|
|
|
|
|
u16 ClkLoopCnt;
|
|
|
|
|
s32 Status;
|
|
|
|
|
u16 ReadReg;
|
|
|
|
|
|
|
|
|
@ -682,6 +654,12 @@ s32 XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq)
|
|
|
|
|
XSDPS_CLK_CTRL_OFFSET, ClockReg);
|
|
|
|
|
|
|
|
|
|
if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) {
|
|
|
|
|
#if defined (ARMR5) || defined (__aarch64__)
|
|
|
|
|
if ((InstancePtr->Mode != XSDPS_DEFAULT_SPEED_MODE) &&
|
|
|
|
|
(InstancePtr->Mode != XSDPS_UHS_SPEED_MODE_SDR12))
|
|
|
|
|
/* Program the Tap delays */
|
|
|
|
|
XSdPs_SetTapDelay(InstancePtr);
|
|
|
|
|
#endif
|
|
|
|
|
/* Calculate divisor */
|
|
|
|
|
for (DivCnt = 0x1U; DivCnt <= XSDPS_CC_EXT_MAX_DIV_CNT;DivCnt++) {
|
|
|
|
|
if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) {
|
|
|
|
@ -890,6 +868,110 @@ s32 XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* API to write EXT_CSD register of eMMC.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param InstancePtr is a pointer to the XSdPs instance.
|
|
|
|
|
* @param Arg is the argument to be sent along with the command
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* - XST_SUCCESS if successful.
|
|
|
|
|
* - XST_FAILURE if fail.
|
|
|
|
|
*
|
|
|
|
|
* @note None.
|
|
|
|
|
*
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
s32 XSdPs_Set_Mmc_ExtCsd(XSdPs *InstancePtr, u32 Arg)
|
|
|
|
|
{
|
|
|
|
|
s32 Status;
|
|
|
|
|
u32 StatusReg;
|
|
|
|
|
|
|
|
|
|
Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);
|
|
|
|
|
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) != 0U) {
|
|
|
|
|
/*
|
|
|
|
|
* 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) == 0U);
|
|
|
|
|
|
|
|
|
|
/* Write to clear bit */
|
|
|
|
|
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
|
|
|
|
|
|
|
|
|
|
Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_RESP0_OFFSET);
|
|
|
|
|
|
|
|
|
|
Status = XST_SUCCESS;
|
|
|
|
|
|
|
|
|
|
RETURN_PATH:
|
|
|
|
|
return Status;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined (ARMR5) || defined (__aarch64__)
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* API to Identify the supported UHS mode. This API will assign the
|
|
|
|
|
* corresponding tap delay API to the Config_TapDelay pointer based on the
|
|
|
|
|
* supported bus speed.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param InstancePtr is a pointer to the XSdPs instance.
|
|
|
|
|
* @param ReadBuff contains the response for CMD6
|
|
|
|
|
*
|
|
|
|
|
* @return None.
|
|
|
|
|
*
|
|
|
|
|
* @note None.
|
|
|
|
|
*
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
void XSdPs_Identify_UhsMode(XSdPs *InstancePtr, u8 *ReadBuff)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Xil_AssertVoid(InstancePtr != NULL);
|
|
|
|
|
|
|
|
|
|
if (((ReadBuff[13] & UHS_SDR104_SUPPORT) != 0U) &&
|
|
|
|
|
(InstancePtr->Config.InputClockHz >= XSDPS_MMC_HS200_MAX_CLK)) {
|
|
|
|
|
InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_SDR104;
|
|
|
|
|
InstancePtr->Config_TapDelay = XSdPs_sdr104_hs200_tapdelay;
|
|
|
|
|
}
|
|
|
|
|
else if (((ReadBuff[13] & UHS_SDR50_SUPPORT) != 0U) &&
|
|
|
|
|
(InstancePtr->Config.InputClockHz >= XSDPS_SD_SDR50_MAX_CLK)) {
|
|
|
|
|
InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_SDR50;
|
|
|
|
|
InstancePtr->Config_TapDelay = XSdPs_sdr50_tapdelay;
|
|
|
|
|
}
|
|
|
|
|
else if (((ReadBuff[13] & UHS_DDR50_SUPPORT) != 0U) &&
|
|
|
|
|
(InstancePtr->Config.InputClockHz >= XSDPS_SD_DDR50_MAX_CLK)) {
|
|
|
|
|
InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_DDR50;
|
|
|
|
|
InstancePtr->Config_TapDelay = XSdPs_ddr50_tapdelay;
|
|
|
|
|
}
|
|
|
|
|
else if (((ReadBuff[13] & UHS_SDR25_SUPPORT) != 0U) &&
|
|
|
|
|
(InstancePtr->Config.InputClockHz >= XSDPS_SD_SDR25_MAX_CLK)) {
|
|
|
|
|
InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_SDR25;
|
|
|
|
|
InstancePtr->Config_TapDelay = XSdPs_hsd_sdr25_tapdelay;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_SDR12;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
@ -1008,7 +1090,7 @@ s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if((Mode == XSDPS_UHS_SPEED_MODE_SDR104) ||
|
|
|
|
|
(Mode == XSDPS_UHS_SPEED_MODE_DDR50)) {
|
|
|
|
|
(Mode == XSDPS_UHS_SPEED_MODE_SDR50)) {
|
|
|
|
|
/* Send tuning pattern */
|
|
|
|
|
Status = XSdPs_Execute_Tuning(InstancePtr);
|
|
|
|
|
if (Status != XST_SUCCESS) {
|
|
|
|
@ -1022,22 +1104,18 @@ s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode)
|
|
|
|
|
RETURN_PATH:
|
|
|
|
|
return Status;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)
|
|
|
|
|
{
|
|
|
|
|
s32 Status;
|
|
|
|
|
u32 StatusReg;
|
|
|
|
|
u32 Arg;
|
|
|
|
|
u16 BlkCnt;
|
|
|
|
|
u16 BlkSize;
|
|
|
|
|
s32 LoopCnt;
|
|
|
|
|
u16 CtrlReg;
|
|
|
|
|
u8 TuningCount;
|
|
|
|
|
|
|
|
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
|
|
|
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
|
|
|
|
|
|
|
|
|
BlkCnt = XSDPS_TUNING_CMD_BLKCNT;
|
|
|
|
|
BlkSize = XSDPS_TUNING_CMD_BLKSIZE;
|
|
|
|
|
if(InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH)
|
|
|
|
|
{
|
|
|
|
@ -1056,6 +1134,18 @@ static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)
|
|
|
|
|
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_HOST_CTRL2_OFFSET, CtrlReg);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* workaround which can work for 1.0/2.0 silicon for auto tuning.
|
|
|
|
|
* This can be revisited for 3.0 silicon if necessary.
|
|
|
|
|
*/
|
|
|
|
|
/* Wait for ~60 clock cycles to reset the tap values */
|
|
|
|
|
(void)usleep(1U);
|
|
|
|
|
|
|
|
|
|
#if defined (ARMR5) || defined (__aarch64__)
|
|
|
|
|
/* Issue DLL Reset to load new SDHC tuned tap values */
|
|
|
|
|
XSdPs_DllReset(InstancePtr);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (TuningCount = 0U; TuningCount < MAX_TUNING_COUNT; TuningCount++) {
|
|
|
|
|
|
|
|
|
|
if (InstancePtr->CardType == XSDPS_CARD_SD) {
|
|
|
|
@ -1073,6 +1163,13 @@ static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)
|
|
|
|
|
XSDPS_HOST_CTRL2_OFFSET) & XSDPS_HC2_EXEC_TNG_MASK) == 0U) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TuningCount == 31) {
|
|
|
|
|
#if defined (ARMR5) || defined (__aarch64__)
|
|
|
|
|
/* Issue DLL Reset to load new SDHC tuned tap values */
|
|
|
|
|
XSdPs_DllReset(InstancePtr);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
|
|
|
|
@ -1081,25 +1178,13 @@ static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)
|
|
|
|
|
goto RETURN_PATH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* As per controller erratum, program the "SDCLK Frequency
|
|
|
|
|
* Select" of clock control register with a value, say
|
|
|
|
|
* clock/2. Wait for the Internal clock stable and program
|
|
|
|
|
* the desired frequency.
|
|
|
|
|
*/
|
|
|
|
|
CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_HOST_CTRL2_OFFSET);
|
|
|
|
|
if ((CtrlReg & XSDPS_HC2_SAMP_CLK_SEL_MASK) != 0U) {
|
|
|
|
|
Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed/2);
|
|
|
|
|
if (Status != XST_SUCCESS) {
|
|
|
|
|
goto RETURN_PATH ;
|
|
|
|
|
}
|
|
|
|
|
Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
|
|
|
|
|
if (Status != XST_SUCCESS) {
|
|
|
|
|
goto RETURN_PATH ;
|
|
|
|
|
}
|
|
|
|
|
/* Wait for ~12 clock cycles to synchronize the new tap values */
|
|
|
|
|
(void)usleep(1U);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#if defined (ARMR5) || defined (__aarch64__)
|
|
|
|
|
/* Issue DLL Reset to load new SDHC tuned tap values */
|
|
|
|
|
XSdPs_DllReset(InstancePtr);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Status = XST_SUCCESS;
|
|
|
|
|
|
|
|
|
@ -1107,7 +1192,226 @@ static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined (__arm__) || defined (__aarch64__)
|
|
|
|
|
#if defined (ARMR5) || defined (__aarch64__)
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* API to set Tap Delay for SDR104 and HS200 modes
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param InstancePtr is a pointer to the XSdPs instance.
|
|
|
|
|
*
|
|
|
|
|
* @return None
|
|
|
|
|
*
|
|
|
|
|
* @note None.
|
|
|
|
|
*
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
void XSdPs_sdr104_hs200_tapdelay(u32 Bank, u32 DeviceId, u32 CardType)
|
|
|
|
|
{
|
|
|
|
|
u32 TapDelay;
|
|
|
|
|
(void) CardType;
|
|
|
|
|
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
if (DeviceId == 0U) {
|
|
|
|
|
/* Program the OTAPDLY */
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY);
|
|
|
|
|
TapDelay |= SD0_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
if (Bank == 2)
|
|
|
|
|
TapDelay |= SD0_OTAPDLYSEL_HS200_B2;
|
|
|
|
|
else
|
|
|
|
|
TapDelay |= SD0_OTAPDLYSEL_HS200_B0;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
} else {
|
|
|
|
|
#endif
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY);
|
|
|
|
|
TapDelay |= SD1_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
if (Bank == 2)
|
|
|
|
|
TapDelay |= SD1_OTAPDLYSEL_HS200_B2;
|
|
|
|
|
else
|
|
|
|
|
TapDelay |= SD1_OTAPDLYSEL_HS200_B0;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* API to set Tap Delay for SDR50 mode
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param InstancePtr is a pointer to the XSdPs instance.
|
|
|
|
|
*
|
|
|
|
|
* @return None
|
|
|
|
|
*
|
|
|
|
|
* @note None.
|
|
|
|
|
*
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
void XSdPs_sdr50_tapdelay(u32 Bank, u32 DeviceId, u32 CardType)
|
|
|
|
|
{
|
|
|
|
|
u32 TapDelay;
|
|
|
|
|
(void) Bank;
|
|
|
|
|
(void) CardType;
|
|
|
|
|
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
if (DeviceId == 0U) {
|
|
|
|
|
/* Program the OTAPDLY */
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY);
|
|
|
|
|
TapDelay |= SD0_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
TapDelay |= SD0_OTAPDLYSEL_SD50;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
} else {
|
|
|
|
|
#endif
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY);
|
|
|
|
|
TapDelay |= SD1_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
TapDelay |= SD1_OTAPDLYSEL_SD50;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* API to set Tap Delay for DDR50 mode
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param InstancePtr is a pointer to the XSdPs instance.
|
|
|
|
|
*
|
|
|
|
|
* @return None
|
|
|
|
|
*
|
|
|
|
|
* @note None.
|
|
|
|
|
*
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
void XSdPs_ddr50_tapdelay(u32 Bank, u32 DeviceId, u32 CardType)
|
|
|
|
|
{
|
|
|
|
|
u32 TapDelay;
|
|
|
|
|
(void) Bank;
|
|
|
|
|
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
if (DeviceId == 0U) {
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY);
|
|
|
|
|
TapDelay |= SD0_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the ITAPDLY */
|
|
|
|
|
TapDelay |= SD0_ITAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
if (CardType== XSDPS_CARD_SD)
|
|
|
|
|
TapDelay |= SD0_ITAPDLYSEL_SD_DDR50;
|
|
|
|
|
else
|
|
|
|
|
TapDelay |= SD0_ITAPDLYSEL_EMMC_DDR50;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
TapDelay &= ~SD0_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the OTAPDLY */
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY);
|
|
|
|
|
TapDelay |= SD0_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
if (CardType == XSDPS_CARD_SD)
|
|
|
|
|
TapDelay |= SD0_OTAPDLYSEL_SD_DDR50;
|
|
|
|
|
else
|
|
|
|
|
TapDelay |= SD0_OTAPDLYSEL_EMMC_DDR50;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
} else {
|
|
|
|
|
#endif
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY);
|
|
|
|
|
TapDelay |= SD1_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the ITAPDLY */
|
|
|
|
|
TapDelay |= SD1_ITAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
if (CardType == XSDPS_CARD_SD)
|
|
|
|
|
TapDelay |= SD1_ITAPDLYSEL_SD_DDR50;
|
|
|
|
|
else
|
|
|
|
|
TapDelay |= SD1_ITAPDLYSEL_EMMC_DDR50;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
TapDelay &= ~SD1_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the OTAPDLY */
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY);
|
|
|
|
|
TapDelay |= SD1_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
if (CardType == XSDPS_CARD_SD)
|
|
|
|
|
TapDelay |= SD1_OTAPDLYSEL_SD_DDR50;
|
|
|
|
|
else
|
|
|
|
|
TapDelay |= SD1_OTAPDLYSEL_EMMC_DDR50;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* API to set Tap Delay for HSD and SDR25 mode
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param InstancePtr is a pointer to the XSdPs instance.
|
|
|
|
|
*
|
|
|
|
|
* @return None
|
|
|
|
|
*
|
|
|
|
|
* @note None.
|
|
|
|
|
*
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
void XSdPs_hsd_sdr25_tapdelay(u32 Bank, u32 DeviceId, u32 CardType)
|
|
|
|
|
{
|
|
|
|
|
u32 TapDelay;
|
|
|
|
|
(void) Bank;
|
|
|
|
|
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
if (DeviceId == 0U) {
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY);
|
|
|
|
|
TapDelay |= SD0_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the ITAPDLY */
|
|
|
|
|
TapDelay |= SD0_ITAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
TapDelay |= SD0_ITAPDLYSEL_HSD;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
TapDelay &= ~SD0_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the OTAPDLY */
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY);
|
|
|
|
|
TapDelay |= SD0_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
if (CardType == XSDPS_CARD_SD)
|
|
|
|
|
TapDelay |= SD0_OTAPDLYSEL_SD_HSD;
|
|
|
|
|
else
|
|
|
|
|
TapDelay |= SD0_OTAPDLYSEL_EMMC_HSD;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
} else {
|
|
|
|
|
#endif
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY);
|
|
|
|
|
TapDelay |= SD1_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the ITAPDLY */
|
|
|
|
|
TapDelay |= SD1_ITAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
TapDelay |= SD1_ITAPDLYSEL_HSD;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
TapDelay &= ~SD1_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the OTAPDLY */
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY);
|
|
|
|
|
TapDelay |= SD1_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
if (CardType == XSDPS_CARD_SD)
|
|
|
|
|
TapDelay |= SD1_OTAPDLYSEL_SD_HSD;
|
|
|
|
|
else
|
|
|
|
|
TapDelay |= SD1_OTAPDLYSEL_EMMC_HSD;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLY, TapDelay);
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
@ -1123,30 +1427,91 @@ static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
void XSdPs_SetTapDelay(XSdPs *InstancePtr)
|
|
|
|
|
{
|
|
|
|
|
u32 DllCtrl, TapDelay;
|
|
|
|
|
if (InstancePtr->Config.DeviceId == XPAR_XSDPS_0_DEVICE_ID) {
|
|
|
|
|
u32 DllCtrl, BankNum, DeviceId, CardType;
|
|
|
|
|
|
|
|
|
|
BankNum = InstancePtr->Config.BankNumber;
|
|
|
|
|
DeviceId = InstancePtr->Config.DeviceId ;
|
|
|
|
|
CardType = InstancePtr->CardType ;
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
if (DeviceId == 0U) {
|
|
|
|
|
DllCtrl = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL);
|
|
|
|
|
DllCtrl |= SD0_DLL_RST;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL, DllCtrl);
|
|
|
|
|
if(InstancePtr->BusSpeed == XSDPS_MMC_HS200_MAX_CLK) {
|
|
|
|
|
/* Program the ITAPDLY */
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY);
|
|
|
|
|
TapDelay |= SD0_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
TapDelay |= SD0_ITAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
TapDelay &= ~SD0_ITAPCHGWIN;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
|
|
|
|
|
/* Program the OTAPDLY */
|
|
|
|
|
TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLYSEL);
|
|
|
|
|
TapDelay |= SD0_OTAPDLYENA;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLYSEL, TapDelay);
|
|
|
|
|
TapDelay |= SD0_OTAPDLYSEL_HS200;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLYSEL, TapDelay);
|
|
|
|
|
}
|
|
|
|
|
InstancePtr->Config_TapDelay(BankNum, DeviceId, CardType);
|
|
|
|
|
DllCtrl &= ~SD0_DLL_RST;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL, DllCtrl);
|
|
|
|
|
} else {
|
|
|
|
|
#endif
|
|
|
|
|
DllCtrl = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL);
|
|
|
|
|
DllCtrl |= SD1_DLL_RST;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL, DllCtrl);
|
|
|
|
|
InstancePtr->Config_TapDelay(BankNum, DeviceId, CardType);
|
|
|
|
|
DllCtrl &= ~SD1_DLL_RST;
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL, DllCtrl);
|
|
|
|
|
#ifdef XPAR_PSU_SD_0_DEVICE_ID
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* API to reset the DLL
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param InstancePtr is a pointer to the XSdPs instance.
|
|
|
|
|
*
|
|
|
|
|
* @return None
|
|
|
|
|
*
|
|
|
|
|
* @note None.
|
|
|
|
|
*
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
static void XSdPs_DllReset(XSdPs *InstancePtr)
|
|
|
|
|
{
|
|
|
|
|
u32 ClockReg, DllCtrl;
|
|
|
|
|
|
|
|
|
|
/* Disable clock */
|
|
|
|
|
ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_CLK_CTRL_OFFSET);
|
|
|
|
|
ClockReg &= ~XSDPS_CC_SD_CLK_EN_MASK;
|
|
|
|
|
XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_CLK_CTRL_OFFSET, ClockReg);
|
|
|
|
|
|
|
|
|
|
/* Issue DLL Reset to load zero tap values */
|
|
|
|
|
DllCtrl = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL);
|
|
|
|
|
if (InstancePtr->Config.DeviceId == 0U) {
|
|
|
|
|
DllCtrl |= SD0_DLL_RST;
|
|
|
|
|
} else {
|
|
|
|
|
DllCtrl |= SD1_DLL_RST;
|
|
|
|
|
}
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL, DllCtrl);
|
|
|
|
|
|
|
|
|
|
/* Wait for 2 micro seconds */
|
|
|
|
|
(void)usleep(2U);
|
|
|
|
|
|
|
|
|
|
/* Release the DLL out of reset */
|
|
|
|
|
DllCtrl = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL);
|
|
|
|
|
if (InstancePtr->Config.DeviceId == 0U) {
|
|
|
|
|
DllCtrl &= ~SD0_DLL_RST;
|
|
|
|
|
} else {
|
|
|
|
|
DllCtrl &= ~SD1_DLL_RST;
|
|
|
|
|
}
|
|
|
|
|
XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL, DllCtrl);
|
|
|
|
|
|
|
|
|
|
/* Wait for internal clock to stabilize */
|
|
|
|
|
ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_CLK_CTRL_OFFSET);
|
|
|
|
|
while((ClockReg & XSDPS_CC_INT_CLK_STABLE_MASK) == 0U) {
|
|
|
|
|
ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
|
|
|
|
|
XSDPS_CLK_CTRL_OFFSET);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
/** @} */
|