u32 XSdPs_FrameCmd()

in portable/Zynq.2019.3/xsdps.c [169:408]


u32 XSdPs_FrameCmd( XSdPs * InstancePtr,
                    u32 Cmd );
s32 XSdPs_CmdTransfer( XSdPs * InstancePtr,
                       u32 Cmd,
                       u32 Arg,
                       u32 BlkCnt );
void XSdPs_SetupADMA2DescTbl( XSdPs * InstancePtr,
                              u32 BlkCnt,
                              const u8 * Buff );
void XSdPs_SetupADMA2DescTbl64Bit( XSdPs * InstancePtr,
                                   u32 BlkCnt );
extern s32 XSdPs_Uhs_ModeInit( XSdPs * InstancePtr,
                               u8 Mode );
static s32 XSdPs_IdentifyCard( XSdPs * InstancePtr );
static s32 XSdPs_Switch_Voltage( XSdPs * InstancePtr );

#if ( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )

/* Declared in ff_sddisk.c :
 * Function will sleep and get interrupted on a change of
 * the status register.  It will loop until:
 *  1. Expected bit (ulMask) becomes high
 *  2. Time-out reached (normally 2 seconds)
 */
    extern u32 XSdPs_WaitInterrupt( XSdPs * InstancePtr,
                                    u32 ulMask,
                                    u32 ulWait );
    /* Clear the interrupt before using it. */
    extern void XSdPs_ClearInterrupt( XSdPs * InstancePtr );
#else
    #error Please define ffconfigSDIO_DRIVER_USES_INTERRUPT
#endif

u16 TransferMode;
/*****************************************************************************/

/**
 *
 * 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. Default Block size is 512 bytes.
 *
 ******************************************************************************/
s32 XSdPs_CfgInitialize( XSdPs * InstancePtr,
                         XSdPs_Config * ConfigPtr,
                         u32 EffectiveAddr )
{
    s32 Status;
    u8 PowerLevel;
    u8 ReadReg;

    Xil_AssertNonvoid( InstancePtr != NULL );
    Xil_AssertNonvoid( ConfigPtr != NULL );

    /* Set some default values. */
    InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;
    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;
    InstancePtr->Config.BusWidth = ConfigPtr->BusWidth;
    InstancePtr->Config.BankNumber = ConfigPtr->BankNumber;
    InstancePtr->Config.HasEMIO = ConfigPtr->HasEMIO;
    InstancePtr->Config.IsCacheCoherent = ConfigPtr->IsCacheCoherent;
    InstancePtr->SectorCount = 0U;
    InstancePtr->Mode = XSDPS_DEFAULT_SPEED_MODE;
    InstancePtr->OTapDelay = 0U;
    InstancePtr->ITapDelay = 0U;
    InstancePtr->Dma64BitAddr = 0U;

    /* Disable bus power and issue emmc hw reset */
    if( ( XSdPs_ReadReg16( InstancePtr->Config.BaseAddress,
                           XSDPS_HOST_CTRL_VER_OFFSET ) & XSDPS_HC_SPEC_VER_MASK ) ==
        XSDPS_HC_SPEC_V3 )
    {
        XSdPs_WriteReg8( InstancePtr->Config.BaseAddress,
                         XSDPS_POWER_CTRL_OFFSET, XSDPS_PC_EMMC_HW_RST_MASK );
    }
    else
    {
        XSdPs_WriteReg8( InstancePtr->Config.BaseAddress,
                         XSDPS_POWER_CTRL_OFFSET, 0x0 );
    }

    /* Delay to poweroff card */
    ( void ) usleep( 1000U );

    /* "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 */
    ReadReg = XSdPs_ReadReg8( InstancePtr->Config.BaseAddress,
                              XSDPS_SW_RST_OFFSET );

    while( ( ReadReg & XSDPS_SWRST_ALL_MASK ) != 0U )
    {
        ReadReg = XSdPs_ReadReg8( InstancePtr->Config.BaseAddress,
                                  XSDPS_SW_RST_OFFSET );
    }

    /* Host Controller version is read. */
    InstancePtr->HC_Version =
        ( u8 ) ( XSdPs_ReadReg16( InstancePtr->Config.BaseAddress,
                                  XSDPS_HOST_CTRL_VER_OFFSET ) & XSDPS_HC_SPEC_VER_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. */
    if( InstancePtr->HC_Version == XSDPS_HC_SPEC_V3 )
    {
        XSdPs_WriteReg8( InstancePtr->Config.BaseAddress,
                         XSDPS_POWER_CTRL_OFFSET,
                         ( XSDPS_PC_BUS_VSEL_3V3_MASK | XSDPS_PC_BUS_PWR_MASK ) &
                         ~XSDPS_PC_EMMC_HW_RST_MASK );
    }
    else
    {
        XSdPs_WriteReg8( InstancePtr->Config.BaseAddress,
                         XSDPS_POWER_CTRL_OFFSET,
                         XSDPS_PC_BUS_VSEL_3V3_MASK | XSDPS_PC_BUS_PWR_MASK );
    }

    /* Delay before issuing the command after emmc reset */
    if( InstancePtr->HC_Version == XSDPS_HC_SPEC_V3 )
    {
        if( ( InstancePtr->Host_Caps & XSDPS_CAPS_SLOT_TYPE_MASK ) ==
            XSDPS_CAPS_EMB_SLOT )
        {
            usleep( 200 );
        }
    }

    /* 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;
    }

    if( ( InstancePtr->Host_Caps & XSDPS_CAP_VOLT_3V3_MASK ) != 0U )
    {
        PowerLevel = XSDPS_PC_BUS_VSEL_3V3_MASK;
    }
    else if( ( InstancePtr->Host_Caps & XSDPS_CAP_VOLT_3V0_MASK ) != 0U )
    {
        PowerLevel = XSDPS_PC_BUS_VSEL_3V0_MASK;
    }
    else if( ( InstancePtr->Host_Caps & XSDPS_CAP_VOLT_1V8_MASK ) != 0U )
    {
        PowerLevel = XSDPS_PC_BUS_VSEL_1V8_MASK;
    }
    else
    {
        PowerLevel = 0U;
    }

    /* Select voltage based on capability and enable bus power. */
    XSdPs_WriteReg8( InstancePtr->Config.BaseAddress,
                     XSDPS_POWER_CTRL_OFFSET,
                     PowerLevel | XSDPS_PC_BUS_PWR_MASK );

    if( InstancePtr->HC_Version == XSDPS_HC_SPEC_V3 )
    {
        /* Enable ADMA2 in 64bit mode. */
        XSdPs_WriteReg8( InstancePtr->Config.BaseAddress,
                         XSDPS_HOST_CTRL1_OFFSET,
                         XSDPS_HC_DMA_ADMA2_64_MASK );
    }
    else
    {
        /* Enable ADMA2 in 32bit mode. */
        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, 0x0U );
    XSdPs_WriteReg16( InstancePtr->Config.BaseAddress,
                      XSDPS_ERR_INTR_SIG_EN_OFFSET, 0x0U );

    /*
     * Transfer mode register - default value
     * DMA enabled, block count enabled, data direction card to host(read)
     */
    TransferMode = 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;
}