s32 XSdPs_SdCardInitialize()

in portable/Zynq/xsdps.c [338:550]


s32 XSdPs_SdCardInitialize( XSdPs * InstancePtr )
{
    u32 PresentStateReg;
    s32 Status;
    u32 RespOCR;
    u32 CSD[ 4 ];
    u32 Arg;
    u8 ReadReg;

    Xil_AssertNonvoid( InstancePtr != NULL );
    Xil_AssertNonvoid( InstancePtr->IsReady == XIL_COMPONENT_IS_READY );

    if( InstancePtr->Config.CardDetect != 0U )
    {
        /*
         * 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 ) == 0U )
        {
            Status = XST_FAILURE;
            goto RETURN_PATH;
        }
    }

    /* CMD0 no response expected */
    Status = XSdPs_CmdTransfer( InstancePtr, ( u32 ) CMD0, 0U, 0U );

    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, 0U );

    if( ( Status != XST_SUCCESS ) && ( Status != XSDPS_CT_ERROR ) )
    {
        Status = XST_FAILURE;
        goto RETURN_PATH;
    }

    if( Status == XSDPS_CT_ERROR )
    {
        /* "Software reset for all" is initiated */
        XSdPs_WriteReg8( InstancePtr->Config.BaseAddress, XSDPS_SW_RST_OFFSET,
                         XSDPS_SWRST_CMD_LINE_MASK );

        /* Proceed with initialization only after reset is complete */
        ReadReg = XSdPs_ReadReg8( InstancePtr->Config.BaseAddress,
                                  XSDPS_SW_RST_OFFSET );

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

    RespOCR = XSdPs_ReadReg( InstancePtr->Config.BaseAddress,
                             XSDPS_RESP0_OFFSET );

    if( RespOCR != XSDPS_CMD8_VOL_PATTERN )
    {
        InstancePtr->Card_Version = XSDPS_SD_VER_1_0;
    }
    else
    {
        InstancePtr->Card_Version = XSDPS_SD_VER_2_0;
    }

    RespOCR = 0U;

    /* Send ACMD41 while card is still busy with power up */
    while( ( RespOCR & XSDPS_RESPOCR_READY ) == 0U )
    {
        Status = XSdPs_CmdTransfer( InstancePtr, CMD55, 0U, 0U );

        if( Status != XST_SUCCESS )
        {
            Status = XST_FAILURE;
            goto RETURN_PATH;
        }

        Arg = XSDPS_ACMD41_HCS | XSDPS_ACMD41_3V3 | ( 0x1FFU << 15U );

        if( InstancePtr->HC_Version == XSDPS_HC_SPEC_V3 )
        {
            Arg |= XSDPS_OCR_S18;
        }

        /* 0x40300000 - Host High Capacity support & 3.3V window */
        Status = XSdPs_CmdTransfer( InstancePtr, ACMD41,
                                    Arg, 0U );

        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 ) != 0U )
    {
        InstancePtr->HCS = 1U;
    }

    /* There is no support to switch to 1.8V and use UHS mode on 1.0 silicon */
    #ifndef UHS_BROKEN
        if( ( RespOCR & XSDPS_OCR_S18 ) != 0U )
        {
            InstancePtr->Switch1v8 = 1U;
            Status = XSdPs_Switch_Voltage( InstancePtr );

            if( Status != XST_SUCCESS )
            {
                Status = XST_FAILURE;
                goto RETURN_PATH;
            }
        }
    #endif /* ifndef UHS_BROKEN */

    /* CMD2 for Card ID */
    Status = XSdPs_CmdTransfer( InstancePtr, CMD2, 0U, 0U );

    if( Status != XST_SUCCESS )
    {
        Status = XST_FAILURE;
        goto RETURN_PATH;
    }

    InstancePtr->CardID[ 0 ] = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_RESP0_OFFSET );
    InstancePtr->CardID[ 1 ] = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_RESP1_OFFSET );
    InstancePtr->CardID[ 2 ] = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_RESP2_OFFSET );
    InstancePtr->CardID[ 3 ] = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_RESP3_OFFSET );

    do
    {
        Status = XSdPs_CmdTransfer( InstancePtr, CMD3, 0U, 0U );

        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 ) & 0xFFFF0000U;
    } while( InstancePtr->RelCardAddr == 0U );

    Status = XSdPs_CmdTransfer( InstancePtr, CMD9, ( InstancePtr->RelCardAddr ), 0U );

    if( Status != XST_SUCCESS )
    {
        Status = XST_FAILURE;
        goto RETURN_PATH;
    }

    {
        u32 resp[ 4 ];
        /* Put the CSD data in a standard order and analyse them */
        resp[ 0 ] = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_RESP0_OFFSET );
        resp[ 1 ] = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_RESP1_OFFSET );
        resp[ 2 ] = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_RESP2_OFFSET );
        resp[ 3 ] = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_RESP3_OFFSET );
        CSD[ 0 ] = ( resp[ 3 ] << 8 ) | ( resp[ 2 ] >> 24 );
        CSD[ 1 ] = ( resp[ 2 ] << 8 ) | ( resp[ 1 ] >> 24 );
        CSD[ 2 ] = ( resp[ 1 ] << 8 ) | ( resp[ 0 ] >> 24 );
        CSD[ 3 ] = ( resp[ 0 ] << 8 );
        FF_PRINTF( "CSD %08lX %08lX %08lX %08lX\n", CSD[ 0 ], CSD[ 1 ], CSD[ 2 ], CSD[ 3 ] );

        sd_decode_csd( &myCSD, ( u32 * ) CSD );
    }

    {
        u32 resp[ 4 ];
        /* When analysing the Card ID (CID), a field in CSD must be known: mmca_vsn. */
        resp[ 0 ] = ( InstancePtr->CardID[ 3 ] >> 8 );
        resp[ 1 ] = ( InstancePtr->CardID[ 3 ] << 24 ) | ( InstancePtr->CardID[ 2 ] >> 8 );
        resp[ 2 ] = ( InstancePtr->CardID[ 2 ] << 24 ) | ( InstancePtr->CardID[ 1 ] >> 8 );
        resp[ 3 ] = ( InstancePtr->CardID[ 1 ] << 24 ) | ( InstancePtr->CardID[ 0 ] >> 8 );
        FF_PRINTF( "CID %08X %08X %08X %08X\n",
                   ( unsigned ) resp[ 0 ],
                   ( unsigned ) resp[ 1 ],
                   ( unsigned ) resp[ 2 ],
                   ( unsigned ) resp[ 3 ] );

        mmc_decode_cid( &myCSD, &myCID, resp );
    }

    Status = XST_SUCCESS;

RETURN_PATH:
    return Status;
}