s32 XSdPs_SdCardInitialize()

in portable/Zynq.2019.3/xsdps.c [436:712]


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

    Xil_AssertNonvoid( InstancePtr != NULL );
    Xil_AssertNonvoid( InstancePtr->IsReady == XIL_COMPONENT_IS_READY );
    FF_PRINTF( "XSdPs_SdCardInitialize\n" );
    #ifndef UHS_MODE_ENABLE
        InstancePtr->Config.BusWidth = XSDPS_WIDTH_4;
    #endif

    if( ( InstancePtr->HC_Version != XSDPS_HC_SPEC_V3 ) ||
        ( ( InstancePtr->Host_Caps & XSDPS_CAPS_SLOT_TYPE_MASK )
          != XSDPS_CAPS_EMB_SLOT ) )
    {
        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;
    }

    FF_PRINTF( "CMD0 : %d\n", Status );

    /*
     * CMD8; response expected
     * 0x1AA - Supply Voltage 2.7 - 3.6V and AA is pattern
     */
    Status = XSdPs_CmdTransfer( InstancePtr, CMD8,
                                XSDPS_CMD8_VOL_PATTERN, 0U );
    FF_PRINTF( "CMD8 : %d\n", Status );

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

    FF_PRINTF( "Card_Version %d\n", InstancePtr->Card_Version );
    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 );

        /*
         * There is no support to switch to 1.8V and use UHS mode on
         * 1.0 silicon
         */
        if( ( InstancePtr->HC_Version == XSDPS_HC_SPEC_V3 ) &&
            #if defined( ARMR5 ) || ( __aarch64__ ) || ( ARMA53_32 ) || ( PSU_PMU )
                ( XGetPSVersion_Info() > ( u32 ) XPS_VERSION_1 ) &&
            #endif
            ( InstancePtr->Config.BusWidth == XSDPS_WIDTH_8 ) )
        {
            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;
    }

    if( ( RespOCR & XSDPS_OCR_S18 ) != 0U )
    {
        InstancePtr->Switch1v8 = 1U;
        Status = XSdPs_Switch_Voltage( InstancePtr );

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

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

    /*
     * Card specific data is read.
     * Currently not used for any operation.
     */
    #if 0
        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 );

        if( ( ( CSD[ 3 ] & CSD_STRUCT_MASK ) >> 22U ) == 0U )
        {
            BlkLen = 1U << ( ( u32 ) ( CSD[ 2 ] & READ_BLK_LEN_MASK ) >> 8U );
            Mult = 1U << ( ( u32 ) ( ( CSD[ 1 ] & C_SIZE_MULT_MASK ) >> 7U ) + 2U );
            DeviceSize = ( CSD[ 1 ] & C_SIZE_LOWER_MASK ) >> 22U;
            DeviceSize |= ( CSD[ 2 ] & C_SIZE_UPPER_MASK ) << 10U;
            DeviceSize = ( DeviceSize + 1U ) * Mult;
            DeviceSize = DeviceSize * BlkLen;
            InstancePtr->SectorCount = ( DeviceSize / XSDPS_BLK_SIZE_512_MASK );
        }
        else if( ( ( CSD[ 3 ] & CSD_STRUCT_MASK ) >> 22U ) == 1U )
        {
            InstancePtr->SectorCount = ( ( ( CSD[ 1 ] & CSD_V2_C_SIZE_MASK ) >> 8U ) +
                                         1U ) * 1024U;
        }
        else
        {
            Status = XST_FAILURE;
            goto RETURN_PATH;
        }
    #endif /* 0 */

    FF_PRINTF( "Sector count %lu\n", InstancePtr->SectorCount );
    Status = XST_SUCCESS;

RETURN_PATH:
    return Status;
}