示例#1
0
OSStatus host_platform_sdio_transfer( bus_transfer_direction_t direction, sdio_command_t command, sdio_transfer_mode_t mode, sdio_block_size_t block_size, uint32_t argument, /*@null@*/ uint32_t* data, uint16_t data_size, sdio_response_needed_t response_expected, /*@out@*/ /*@null@*/ uint32_t* response )
{
    uint32_t loop_count = 0;
    OSStatus result;
    uint16_t attempts = 0;

    check_string(!((command == SDIO_CMD_53) && (data == NULL)), "Bad args" );

    if ( response != NULL )
    {
        *response = 0;
    }

    platform_mcu_powersave_disable();

    /* Ensure the bus isn't stuck half way through transfer */
    DMA2_Stream3->CR   = 0;

restart:
    SDIO->ICR = (uint32_t) 0xFFFFFFFF;
    sdio_transfer_failed = false;
    ++attempts;

    /* Check if we've tried too many times */
    if (attempts >= (uint16_t) BUS_LEVEL_MAX_RETRIES)
    {
        result = kGeneralErr;
        goto exit;
    }

    /* Prepare the data transfer register */
    current_command = command;
    if ( command == SDIO_CMD_53 )
    {
        sdio_enable_bus_irq();

        /* Dodgy STM32 hack to set the CMD53 byte mode size to be the same as the block size */
        if ( mode == SDIO_BYTE_MODE )
        {
            block_size = find_optimal_block_size( data_size );
            if ( block_size < SDIO_512B_BLOCK )
            {
                argument = ( argument & (uint32_t) ( ~0x1FF ) ) | block_size;
            }
            else
            {
                argument = ( argument & (uint32_t) ( ~0x1FF ) );
            }
        }

        /* Prepare the SDIO for a data transfer */
        current_transfer_direction = direction;
        sdio_prepare_data_transfer( direction, block_size, (uint8_t*) data, data_size );

        /* Send the command */
        SDIO->ARG = argument;
        SDIO->CMD = (uint32_t) ( command | SDIO_Response_Short | SDIO_Wait_No | SDIO_CPSM_Enable );

        /* Wait for the whole transfer to complete */
        result = mico_rtos_get_semaphore( &sdio_transfer_finished_semaphore, (uint32_t) 50 );
        if ( result != kNoErr )
        {
            goto exit;
        }

        if ( sdio_transfer_failed == true )
        {
            goto restart;
        }

        /* Check if there were any SDIO errors */
        require(( SDIO->STA & ( SDIO_STA_DTIMEOUT | SDIO_STA_CTIMEOUT ) ) == 0, restart);
        require_string(( SDIO->STA & ( SDIO_STA_CCRCFAIL | SDIO_STA_DCRCFAIL | SDIO_STA_TXUNDERR | SDIO_STA_RXOVERR ) ) == 0, restart, "SDIO communication failure");

        /* Wait till complete */
        loop_count = (uint32_t) SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS;
        do
        {
            loop_count--;
            if ( loop_count == 0 || ( ( SDIO->STA & SDIO_ERROR_MASK ) != 0 ) )
            {
                goto restart;
            }
        } while ( ( SDIO->STA & ( SDIO_STA_TXACT | SDIO_STA_RXACT ) ) != 0 );

        if ( direction == BUS_READ )
        {
            memcpy( user_data, dma_data_source, (size_t) user_data_size );
        }
    }
    else
    {
        uint32_t temp_sta;

        /* Send the command */
        SDIO->ARG = argument;
        SDIO->CMD = (uint32_t) ( command | SDIO_Response_Short | SDIO_Wait_No | SDIO_CPSM_Enable );

        loop_count = (uint32_t) COMMAND_FINISHED_CMD52_TIMEOUT_LOOPS;
        do
        {
            temp_sta = SDIO->STA;
            loop_count--;
            if ( loop_count == 0 || ( ( response_expected == RESPONSE_NEEDED ) && ( ( temp_sta & SDIO_ERROR_MASK ) != 0 ) ) )
            {
                goto restart;
            }
        } while ( ( temp_sta & SDIO_FLAG_CMDACT ) != 0 );
    }

    if ( response != NULL )
    {
        *response = SDIO->RESP1;
    }
    result = kNoErr;

exit:
    platform_mcu_powersave_enable();
#ifndef SDIO_1_BIT
    SDIO->MASK = SDIO_MASK_SDIOITIE;
#endif
    return result;
}
示例#2
0
wwd_result_t host_platform_sdio_transfer( wwd_bus_transfer_direction_t direction, sdio_command_t command, sdio_transfer_mode_t mode, sdio_block_size_t block_size, uint32_t argument, /*@null@*/ uint32_t* data, uint16_t data_size, sdio_response_needed_t response_expected, /*@out@*/ /*@null@*/ uint32_t* response )
{
    uint8_t error;
    MciCmd *pCommand = &( sdio_command );

    platform_mcu_powersave_disable();
    /*
     direction => BUS_READ, BUS_WRITE,
     command => SDIO_CMD_0, SDIO_CMD_3, SDIO_CMD_5, SDIO_CMD_7, SDIO_CMD_52, SDIO_CMD_53
     mode => SDIO_BLOCK_MODE, SDIO_BYTE_MODE
     block_size => SDIO_1B_BLOCK to SDIO_2048B_BLOCK, we use SDIO_1B_BLOCK and SDIO_64B_BLOCK
     argument => data byte (or 0)
     response_expected => RESPONSE_NEEDED, NO_RESPONSE
     */

    UNUSED_PARAMETER( response_expected );

    reset_sdio_command( pCommand );

    //fill defaults
    pCommand->arg = argument;
    pCommand->pResp = response;

    //clear the response, if any
    if ( response != NULL)
    {
        *response = 0;
    };

    // note: do not forget to properly fill Rx response reg. number to pCommand->resType

    //do the command
    switch ( command )
    {
        case SDIO_CMD_0:
        {
            //CMD 0: typical direction: BUS_WRITE
            pCommand->cmd = ( 0 | HSMCI_CMDR_RSPTYP_48_BIT | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_TRCMD_NO_DATA | HSMCI_CMDR_MAXLAT);

            //pCommand->resType = 1; // nah

            error = send_sdio_command( &sdio_driver, 1 );
            if ( error == 0 )
            {
                platform_mcu_powersave_enable();
                return WICED_SUCCESS;
            };
            break;
        }

        case SDIO_CMD_3:
        {
            //CMD 3: typical direction: BUS_READ
            pCommand->cmd  = 3;
            pCommand->cmd |= HSMCI_CMDR_RSPTYP_48_BIT;
            pCommand->cmd |= HSMCI_CMDR_SPCMD_STD;
            pCommand->cmd |= HSMCI_CMDR_OPDCMD_OPENDRAIN;
            pCommand->cmd |= HSMCI_CMDR_MAXLAT_64;
            pCommand->cmd |= HSMCI_CMDR_TRCMD_NO_DATA;
            pCommand->cmd |= (direction==BUS_READ)?HSMCI_CMDR_TRDIR_READ:HSMCI_CMDR_TRDIR_WRITE;
            pCommand->cmd |= HSMCI_CMDR_TRTYP_BYTE;
            pCommand->cmd |= HSMCI_CMDR_IOSPCMD_STD;
            pCommand->cmd |= HSMCI_CMDR_ATACS_NORMAL;


            pCommand->resType = 6;

            error = send_sdio_command( &sdio_driver, 0 );
            if ( error == SDMMC_ERROR_NORESPONSE )
            {
                platform_mcu_powersave_enable();
                return WICED_TIMEOUT;
            }
            else if ( error == 0 )
            {
                platform_mcu_powersave_enable();
                return WICED_SUCCESS;
            };
            break;
        }

        case SDIO_CMD_5:
        {
            //CMD 5: typical direction: BUS_READ
            pCommand->cmd = ( 5 | HSMCI_CMDR_RSPTYP_R1B | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_MAXLAT | HSMCI_CMDR_TRCMD_NO_DATA );
            pCommand->resType = 4;

            error = send_sdio_command( &sdio_driver, 1 );
            if ( error == 0 )
            {
                platform_mcu_powersave_enable();
                return WICED_SUCCESS;
            };
            break;
        }

        case SDIO_CMD_7:
        {
            //CMD 7: typical direction: BUS_WRITE
            pCommand->cmd = ( 7 | HSMCI_CMDR_RSPTYP_R1B | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_MAXLAT | HSMCI_CMDR_TRCMD_NO_DATA );
            pCommand->resType = 1;

            error = send_sdio_command( &sdio_driver, 1 );
            if ( error == 0 )
            {
                platform_mcu_powersave_enable();
                return WICED_SUCCESS;
            };
            break;
        }

        case SDIO_CMD_52:
        {
            //CMD 52: typical direction: BOTH
            pCommand->cmd = ( 52 | HSMCI_CMDR_RSPTYP_48_BIT | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_MAXLAT | HSMCI_CMDR_TRCMD_NO_DATA );
            pCommand->resType = 5;

            error = send_sdio_command( &sdio_driver, 1 );
            if ( error == 0 )
            {
                platform_mcu_powersave_enable();
                return WICED_SUCCESS;
            };
            break;
        }

        case SDIO_CMD_53:
        {
            //specific

            pCommand->cmd = ( 53 | HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_RSPTYP_48_BIT | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_MAXLAT );

            /* Write/Read operation */
            if ( direction == BUS_WRITE )
            {
                pCommand->tranType = MCI_START_WRITE;
            }
            else
            {
                pCommand->cmd |= HSMCI_CMDR_TRDIR;
                pCommand->tranType = MCI_START_READ;
            }

            /* Always Block mode */
            pCommand->cmd |= HSMCI_CMDR_TRTYP_BLOCK | HSMCI_CMDR_TRCMD_START_DATA;

            if ( mode == SDIO_BYTE_MODE )
            {
                /* Dodgy STM32 hack to set the CMD53 byte mode size to be the same as the block size */
                pCommand->cmd |= HSMCI_CMDR_TRTYP_BYTE;
                block_size = find_optimal_block_size( data_size );
                if ( block_size < SDIO_512B_BLOCK )
                {
                    pCommand->arg = ( pCommand->arg & (uint32_t) ( ~0x1FF ) ) | block_size;
                }
                else
                {
                    pCommand->arg = ( pCommand->arg & (uint32_t) ( ~0x1FF ) );
                }

                // compute block count
                pCommand->blockSize = block_size;
                pCommand->nbBlock = ( data_size / block_size );
                if ( ( pCommand->nbBlock * block_size ) < data_size )
                {
                    pCommand->nbBlock++;
                };
            }
            else
            {

              // compute block count
              pCommand->blockSize = block_size;
              pCommand->nbBlock = ( data_size / block_size );
              if ( ( pCommand->nbBlock * block_size ) < data_size )
              {
                  pCommand->nbBlock++;
              };
            }

            pCommand->resType = 5; //select the response register

            /* Set the DMA data pointer to the temp data for SDIO read */
            if ( direction == BUS_WRITE )
            {
                pCommand->pData = (unsigned char *)data;
            }
            else
            {
                pCommand->pData = (unsigned char *)temp_sdio_rx_buffer;
            }

            error = send_sdio_command( &sdio_driver, 0 );
            if ( error == 0 )
            {
                if ( direction == BUS_READ )
                {
                    /* Copy the data read by DMA to the buffer */
                    memcpy( (void *) data, (void *) temp_sdio_rx_buffer, data_size );
                }

                platform_mcu_powersave_enable();
                return WICED_SUCCESS;
            }

            break;
        }

        case __MAX_VAL:
            break;
        default:
//            WICED_ERROR_PRINT_DEBUG_ONLY(( "\n INVALID SDIO CMD \n" ));
            break;
    }

    platform_mcu_powersave_enable();

    return WICED_ERROR;
}