From 716ca530e1c4515d8683c9d5be3d56b301758b66 Mon Sep 17 00:00:00 2001 From: James <> Date: Wed, 4 Nov 2015 11:49:21 +0000 Subject: trunk-47381 --- target/linux/at91/image/dfboot/src/mci_device.c | 743 ++++++++++++++++++++++++ 1 file changed, 743 insertions(+) create mode 100644 target/linux/at91/image/dfboot/src/mci_device.c (limited to 'target/linux/at91/image/dfboot/src/mci_device.c') diff --git a/target/linux/at91/image/dfboot/src/mci_device.c b/target/linux/at91/image/dfboot/src/mci_device.c new file mode 100644 index 0000000..cce74a3 --- /dev/null +++ b/target/linux/at91/image/dfboot/src/mci_device.c @@ -0,0 +1,743 @@ +//*---------------------------------------------------------------------------- +//* ATMEL Microcontroller Software Support - ROUSSET - +//*---------------------------------------------------------------------------- +//* The software is delivered "AS IS" without warranty or condition of any +//* kind, either express, implied or statutory. This includes without +//* limitation any warranty or condition with respect to merchantability or +//* fitness for any particular purpose, or against the infringements of +//* intellectual property rights of others. +//*---------------------------------------------------------------------------- +//* File Name : mci_device.c +//* Object : TEST DataFlash Functions +//* Creation : FB 26/11/2002 +//* +//*---------------------------------------------------------------------------- + +#include +#include "stdio.h" + +#define AT91C_MCI_TIMEOUT 1000000 /* For AT91F_MCIDeviceWaitReady */ +#define BUFFER_SIZE_MCI_DEVICE 512 +#define MASTER_CLOCK 60000000 +#define FALSE 0 +#define TRUE 1 + +//* External Functions +extern void AT91F_ASM_MCI_Handler(void); +//* Global Variables +AT91S_MciDeviceFeatures MCI_Device_Features; +AT91S_MciDeviceDesc MCI_Device_Desc; +AT91S_MciDevice MCI_Device; + +#undef ENABLE_WRITE +#undef MMC + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_SendCommand +//* \brief Generic function to send a command to the MMC or SDCard +//*---------------------------------------------------------------------------- +int AT91F_MCI_SendCommand ( + AT91PS_MciDevice pMCI_Device, + unsigned int Cmd, + unsigned int Arg) +{ + unsigned int error,status; + //unsigned int tick=0; + + // Send the command + AT91C_BASE_MCI->MCI_ARGR = Arg; + AT91C_BASE_MCI->MCI_CMDR = Cmd; + + // wait for CMDRDY Status flag to read the response + do + { + status = AT91C_BASE_MCI->MCI_SR; + //tick++; + } + while( !(status & AT91C_MCI_CMDRDY) );//&& (tick<100) ); + + // Test error ==> if crc error and response R3 ==> don't check error + error = (AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR; + if(error != 0 ) + { + // if the command is SEND_OP_COND the CRC error flag is always present (cf : R3 response) + if ( (Cmd != AT91C_SDCARD_APP_OP_COND_CMD) && (Cmd != AT91C_MMC_SEND_OP_COND_CMD) ) + return ((AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR); + else + { + if (error != AT91C_MCI_RCRCE) + return ((AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR); + } + } + return AT91C_CMD_SEND_OK; +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_SDCard_SendAppCommand +//* \brief Specific function to send a specific command to the SDCard +//*---------------------------------------------------------------------------- +int AT91F_MCI_SDCard_SendAppCommand ( + AT91PS_MciDevice pMCI_Device, + unsigned int Cmd_App, + unsigned int Arg ) +{ + unsigned int status; + //unsigned int tick=0; + + // Send the CMD55 for application specific command + AT91C_BASE_MCI->MCI_ARGR = (pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address << 16 ); + AT91C_BASE_MCI->MCI_CMDR = AT91C_APP_CMD; + + // wait for CMDRDY Status flag to read the response + do + { + status = AT91C_BASE_MCI->MCI_SR; + //tick++; + } + while( !(status & AT91C_MCI_CMDRDY) );//&& (tick<100) ); + + // if an error occurs + if (((AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR) != 0 ) + return ((AT91C_BASE_MCI->MCI_SR) & AT91C_MCI_SR_ERROR); + + // check if it is a specific command and then send the command + if ( (Cmd_App && AT91C_SDCARD_APP_ALL_CMD) == 0) + return AT91C_CMD_SEND_ERROR; + + return( AT91F_MCI_SendCommand(pMCI_Device,Cmd_App,Arg) ); +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_GetStatus +//* \brief Addressed card sends its status register +//*---------------------------------------------------------------------------- +int AT91F_MCI_GetStatus(AT91PS_MciDevice pMCI_Device,unsigned int relative_card_address) +{ + if (AT91F_MCI_SendCommand(pMCI_Device, + AT91C_SEND_STATUS_CMD, + relative_card_address <<16) == AT91C_CMD_SEND_OK) + return (AT91C_BASE_MCI->MCI_RSPR[0]); + + return AT91C_CMD_SEND_ERROR; +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_Device_Handler +//* \brief MCI C interrupt handler +//*---------------------------------------------------------------------------- +void AT91F_MCI_Device_Handler( + AT91PS_MciDevice pMCI_Device, + unsigned int status) +{ + // If End of Tx Buffer Empty interrupt occurred + if ( status & AT91C_MCI_TXBUFE ) + { + AT91C_BASE_MCI->MCI_IDR = AT91C_MCI_TXBUFE; + AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_TXTDIS; + + pMCI_Device->pMCI_DeviceDesc->state = AT91C_MCI_IDLE; + } // End of if AT91C_MCI_TXBUFF + + // If End of Rx Buffer Full interrupt occurred + if ( status & AT91C_MCI_RXBUFF ) + { + AT91C_BASE_MCI->MCI_IDR = AT91C_MCI_RXBUFF; + AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_RXTDIS; + + pMCI_Device->pMCI_DeviceDesc->state = AT91C_MCI_IDLE; + } // End of if AT91C_MCI_RXBUFF + +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_Handler +//* \brief MCI Handler +//*---------------------------------------------------------------------------- +void AT91F_MCI_Handler(void) +{ + int status; + + status = ( AT91C_BASE_MCI->MCI_SR & AT91C_BASE_MCI->MCI_IMR ); + + AT91F_MCI_Device_Handler(&MCI_Device,status); +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_ReadBlock +//* \brief Read an ENTIRE block or PARTIAL block +//*---------------------------------------------------------------------------- +int AT91F_MCI_ReadBlock( + AT91PS_MciDevice pMCI_Device, + int src, + unsigned int *dataBuffer, + int sizeToRead ) +{ + //////////////////////////////////////////////////////////////////////////////////////////// + if(pMCI_Device->pMCI_DeviceDesc->state != AT91C_MCI_IDLE) + return AT91C_READ_ERROR; + + if( (AT91F_MCI_GetStatus(pMCI_Device,pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address) & AT91C_SR_READY_FOR_DATA) != AT91C_SR_READY_FOR_DATA) + return AT91C_READ_ERROR; + + if ( (src + sizeToRead) > pMCI_Device->pMCI_DeviceFeatures->Memory_Capacity ) + return AT91C_READ_ERROR; + + // If source does not fit a begin of a block + if ( (src % pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length) != 0 ) + return AT91C_READ_ERROR; + + // Test if the MMC supports Partial Read Block + // ALWAYS SUPPORTED IN SD Memory Card + if( (sizeToRead < pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length) + && (pMCI_Device->pMCI_DeviceFeatures->Read_Partial == 0x00) ) + return AT91C_READ_ERROR; + + if( sizeToRead > pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length) + return AT91C_READ_ERROR; + //////////////////////////////////////////////////////////////////////////////////////////// + + // Init Mode Register + AT91C_BASE_MCI->MCI_MR |= ((pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length << 16) | AT91C_MCI_PDCMODE); + + if (sizeToRead %4) + sizeToRead = (sizeToRead /4)+1; + else + sizeToRead = sizeToRead/4; + + AT91C_BASE_PDC_MCI->PDC_PTCR = (AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS); + AT91C_BASE_PDC_MCI->PDC_RPR = (unsigned int)dataBuffer; + AT91C_BASE_PDC_MCI->PDC_RCR = sizeToRead; + + // Send the Read single block command + if ( AT91F_MCI_SendCommand(pMCI_Device, AT91C_READ_SINGLE_BLOCK_CMD, src) != AT91C_CMD_SEND_OK ) + return AT91C_READ_ERROR; + + pMCI_Device->pMCI_DeviceDesc->state = AT91C_MCI_RX_SINGLE_BLOCK; + + // Enable AT91C_MCI_RXBUFF Interrupt + AT91C_BASE_MCI->MCI_IER = AT91C_MCI_RXBUFF; + + // (PDC) Receiver Transfer Enable + AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_RXTEN; + + return AT91C_READ_OK; +} + + +#ifdef ENABLE_WRITE +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_WriteBlock +//* \brief Write an ENTIRE block but not always PARTIAL block !!! +//*---------------------------------------------------------------------------- +int AT91F_MCI_WriteBlock( + AT91PS_MciDevice pMCI_Device, + int dest, + unsigned int *dataBuffer, + int sizeToWrite ) +{ + //////////////////////////////////////////////////////////////////////////////////////////// + if( pMCI_Device->pMCI_DeviceDesc->state != AT91C_MCI_IDLE) + return AT91C_WRITE_ERROR; + + if( (AT91F_MCI_GetStatus(pMCI_Device,pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address) & AT91C_SR_READY_FOR_DATA) != AT91C_SR_READY_FOR_DATA) + return AT91C_WRITE_ERROR; + + if ( (dest + sizeToWrite) > pMCI_Device->pMCI_DeviceFeatures->Memory_Capacity ) + return AT91C_WRITE_ERROR; + + // If source does not fit a begin of a block + if ( (dest % pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length) != 0 ) + return AT91C_WRITE_ERROR; + + // Test if the MMC supports Partial Write Block + if( (sizeToWrite < pMCI_Device->pMCI_DeviceFeatures->Max_Write_DataBlock_Length) + && (pMCI_Device->pMCI_DeviceFeatures->Write_Partial == 0x00) ) + return AT91C_WRITE_ERROR; + + if( sizeToWrite > pMCI_Device->pMCI_DeviceFeatures->Max_Write_DataBlock_Length ) + return AT91C_WRITE_ERROR; + //////////////////////////////////////////////////////////////////////////////////////////// + + // Init Mode Register + AT91C_BASE_MCI->MCI_MR |= ((pMCI_Device->pMCI_DeviceFeatures->Max_Write_DataBlock_Length << 16) | AT91C_MCI_PDCMODE); + + if (sizeToWrite %4) + sizeToWrite = (sizeToWrite /4)+1; + else + sizeToWrite = sizeToWrite/4; + + // Init PDC for write sequence + AT91C_BASE_PDC_MCI->PDC_PTCR = (AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS); + AT91C_BASE_PDC_MCI->PDC_TPR = (unsigned int) dataBuffer; + AT91C_BASE_PDC_MCI->PDC_TCR = sizeToWrite; + + // Send the write single block command + if ( AT91F_MCI_SendCommand(pMCI_Device, AT91C_WRITE_BLOCK_CMD, dest) != AT91C_CMD_SEND_OK) + return AT91C_WRITE_ERROR; + + pMCI_Device->pMCI_DeviceDesc->state = AT91C_MCI_TX_SINGLE_BLOCK; + + // Enable AT91C_MCI_TXBUFE Interrupt + AT91C_BASE_MCI->MCI_IER = AT91C_MCI_TXBUFE; + + // Enables TX for PDC transfert requests + AT91C_BASE_PDC_MCI->PDC_PTCR = AT91C_PDC_TXTEN; + + return AT91C_WRITE_OK; +} +#endif + +#ifdef MMC +//*------------------------------------------------------------------------------------------------------------ +//* \fn AT91F_MCI_MMC_SelectCard +//* \brief Toggles a card between the Stand_by and Transfer states or between Programming and Disconnect states +//*------------------------------------------------------------------------------------------------------------ +int AT91F_MCI_MMC_SelectCard(AT91PS_MciDevice pMCI_Device, unsigned int relative_card_address) +{ + int status; + + //* Check if the MMC card chosen is already the selected one + status = AT91F_MCI_GetStatus(pMCI_Device,relative_card_address); + + if (status < 0) + return AT91C_CARD_SELECTED_ERROR; + + if ((status & AT91C_SR_CARD_SELECTED) == AT91C_SR_CARD_SELECTED) + return AT91C_CARD_SELECTED_OK; + + //* Search for the MMC Card to be selected, status = the Corresponding Device Number + status = 0; + while( (pMCI_Device->pMCI_DeviceFeatures[status].Relative_Card_Address != relative_card_address) + && (status < AT91C_MAX_MCI_CARDS) ) + status++; + + if (status > AT91C_MAX_MCI_CARDS) + return AT91C_CARD_SELECTED_ERROR; + + if (AT91F_MCI_SendCommand( pMCI_Device, + AT91C_SEL_DESEL_CARD_CMD, + pMCI_Device->pMCI_DeviceFeatures[status].Relative_Card_Address << 16) == AT91C_CMD_SEND_OK) + return AT91C_CARD_SELECTED_OK; + return AT91C_CARD_SELECTED_ERROR; +} +#endif + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_GetCSD +//* \brief Asks to the specified card to send its CSD +//*---------------------------------------------------------------------------- +int AT91F_MCI_GetCSD (AT91PS_MciDevice pMCI_Device, unsigned int relative_card_address , unsigned int * response) +{ + + if(AT91F_MCI_SendCommand(pMCI_Device, + AT91C_SEND_CSD_CMD, + (relative_card_address << 16)) != AT91C_CMD_SEND_OK) + return AT91C_CMD_SEND_ERROR; + + response[0] = AT91C_BASE_MCI->MCI_RSPR[0]; + response[1] = AT91C_BASE_MCI->MCI_RSPR[1]; + response[2] = AT91C_BASE_MCI->MCI_RSPR[2]; + response[3] = AT91C_BASE_MCI->MCI_RSPR[3]; + + return AT91C_CMD_SEND_OK; +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_SetBlocklength +//* \brief Select a block length for all following block commands (R/W) +//*---------------------------------------------------------------------------- +int AT91F_MCI_SetBlocklength(AT91PS_MciDevice pMCI_Device,unsigned int length) +{ + return( AT91F_MCI_SendCommand(pMCI_Device, AT91C_SET_BLOCKLEN_CMD, length) ); +} + +#ifdef MMC +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_MMC_GetAllOCR +//* \brief Asks to all cards to send their operations conditions +//*---------------------------------------------------------------------------- +int AT91F_MCI_MMC_GetAllOCR (AT91PS_MciDevice pMCI_Device) +{ + unsigned int response =0x0; + + while(1) + { + response = AT91F_MCI_SendCommand(pMCI_Device, + AT91C_MMC_SEND_OP_COND_CMD, + AT91C_MMC_HOST_VOLTAGE_RANGE); + if (response != AT91C_CMD_SEND_OK) + return AT91C_INIT_ERROR; + + response = AT91C_BASE_MCI->MCI_RSPR[0]; + + if ( (response & AT91C_CARD_POWER_UP_BUSY) == AT91C_CARD_POWER_UP_BUSY) + return(response); + } +} +#endif + +#ifdef MMC +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_MMC_GetAllCID +//* \brief Asks to the MMC on the chosen slot to send its CID +//*---------------------------------------------------------------------------- +int AT91F_MCI_MMC_GetAllCID (AT91PS_MciDevice pMCI_Device, unsigned int *response) +{ + int Nb_Cards_Found=-1; + + while(1) + { + if(AT91F_MCI_SendCommand(pMCI_Device, + AT91C_MMC_ALL_SEND_CID_CMD, + AT91C_NO_ARGUMENT) != AT91C_CMD_SEND_OK) + return Nb_Cards_Found; + else + { + Nb_Cards_Found = 0; + //* Assignation of the relative address to the MMC CARD + pMCI_Device->pMCI_DeviceFeatures[Nb_Cards_Found].Relative_Card_Address = Nb_Cards_Found + AT91C_FIRST_RCA; + //* Set the insert flag + pMCI_Device->pMCI_DeviceFeatures[Nb_Cards_Found].Card_Inserted = AT91C_MMC_CARD_INSERTED; + + if (AT91F_MCI_SendCommand(pMCI_Device, + AT91C_MMC_SET_RELATIVE_ADDR_CMD, + (Nb_Cards_Found + AT91C_FIRST_RCA) << 16) != AT91C_CMD_SEND_OK) + return AT91C_CMD_SEND_ERROR; + + //* If no error during assignation address ==> Increment Nb_cards_Found + Nb_Cards_Found++ ; + } + } +} +#endif +#ifdef MMC +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_MMC_Init +//* \brief Return the MMC initialisation status +//*---------------------------------------------------------------------------- +int AT91F_MCI_MMC_Init (AT91PS_MciDevice pMCI_Device) +{ + unsigned int tab_response[4]; + unsigned int mult,blocknr; + unsigned int i,Nb_Cards_Found=0; + + //* Resets all MMC Cards in Idle state + AT91F_MCI_SendCommand(pMCI_Device, AT91C_MMC_GO_IDLE_STATE_CMD, AT91C_NO_ARGUMENT); + + if(AT91F_MCI_MMC_GetAllOCR(pMCI_Device) == AT91C_INIT_ERROR) + return AT91C_INIT_ERROR; + + Nb_Cards_Found = AT91F_MCI_MMC_GetAllCID(pMCI_Device,tab_response); + if (Nb_Cards_Found != AT91C_CMD_SEND_ERROR) + { + //* Set the Mode Register + AT91C_BASE_MCI->MCI_MR = AT91C_MCI_MR_PDCMODE; + + for(i = 0; i < Nb_Cards_Found; i++) + { + if (AT91F_MCI_GetCSD(pMCI_Device, + pMCI_Device->pMCI_DeviceFeatures[i].Relative_Card_Address, + tab_response) != AT91C_CMD_SEND_OK) + pMCI_Device->pMCI_DeviceFeatures[i].Relative_Card_Address = 0; + else + { + pMCI_Device->pMCI_DeviceFeatures[i].Max_Read_DataBlock_Length = 1 << ((tab_response[1] >> AT91C_CSD_RD_B_LEN_S) & AT91C_CSD_RD_B_LEN_M ); + pMCI_Device->pMCI_DeviceFeatures[i].Max_Write_DataBlock_Length = 1 << ((tab_response[3] >> AT91C_CSD_WBLEN_S) & AT91C_CSD_WBLEN_M ); + pMCI_Device->pMCI_DeviceFeatures[i].Sector_Size = 1 + ((tab_response[2] >> AT91C_CSD_v22_SECT_SIZE_S) & AT91C_CSD_v22_SECT_SIZE_M ); + pMCI_Device->pMCI_DeviceFeatures[i].Read_Partial = (tab_response[1] >> AT91C_CSD_RD_B_PAR_S) & AT91C_CSD_RD_B_PAR_M; + pMCI_Device->pMCI_DeviceFeatures[i].Write_Partial = (tab_response[3] >> AT91C_CSD_WBLOCK_P_S) & AT91C_CSD_WBLOCK_P_M; + + // None in MMC specification version 2.2 + pMCI_Device->pMCI_DeviceFeatures[i].Erase_Block_Enable = 0; + + pMCI_Device->pMCI_DeviceFeatures[i].Read_Block_Misalignment = (tab_response[1] >> AT91C_CSD_RD_B_MIS_S) & AT91C_CSD_RD_B_MIS_M; + pMCI_Device->pMCI_DeviceFeatures[i].Write_Block_Misalignment = (tab_response[1] >> AT91C_CSD_WR_B_MIS_S) & AT91C_CSD_WR_B_MIS_M; + + //// Compute Memory Capacity + // compute MULT + mult = 1 << ( ((tab_response[2] >> AT91C_CSD_C_SIZE_M_S) & AT91C_CSD_C_SIZE_M_M) + 2 ); + // compute MSB of C_SIZE + blocknr = ((tab_response[1] >> AT91C_CSD_CSIZE_H_S) & AT91C_CSD_CSIZE_H_M) << 2; + // compute MULT * (LSB of C-SIZE + MSB already computed + 1) = BLOCKNR + blocknr = mult * ( ( blocknr + ( (tab_response[2] >> AT91C_CSD_CSIZE_L_S) & AT91C_CSD_CSIZE_L_M) ) + 1 ); + + pMCI_Device->pMCI_DeviceFeatures[i].Memory_Capacity = pMCI_Device->pMCI_DeviceFeatures[i].Max_Read_DataBlock_Length * blocknr; + //// End of Compute Memory Capacity + + } // end of else + } // end of for + + return AT91C_INIT_OK; + } // end of if + + return AT91C_INIT_ERROR; +} +#endif + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_SDCard_GetOCR +//* \brief Asks to all cards to send their operations conditions +//*---------------------------------------------------------------------------- +int AT91F_MCI_SDCard_GetOCR (AT91PS_MciDevice pMCI_Device) +{ + unsigned int response =0x0; + + // The RCA to be used for CMD55 in Idle state shall be the card's default RCA=0x0000. + pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address = 0x0; + + while( (response & AT91C_CARD_POWER_UP_BUSY) != AT91C_CARD_POWER_UP_BUSY ) + { + response = AT91F_MCI_SDCard_SendAppCommand(pMCI_Device, + AT91C_SDCARD_APP_OP_COND_CMD, + AT91C_MMC_HOST_VOLTAGE_RANGE); + if (response != AT91C_CMD_SEND_OK) + return AT91C_INIT_ERROR; + + response = AT91C_BASE_MCI->MCI_RSPR[0]; + } + + return(AT91C_BASE_MCI->MCI_RSPR[0]); +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_SDCard_GetCID +//* \brief Asks to the SDCard on the chosen slot to send its CID +//*---------------------------------------------------------------------------- +int AT91F_MCI_SDCard_GetCID (AT91PS_MciDevice pMCI_Device, unsigned int *response) +{ + if(AT91F_MCI_SendCommand(pMCI_Device, + AT91C_ALL_SEND_CID_CMD, + AT91C_NO_ARGUMENT) != AT91C_CMD_SEND_OK) + return AT91C_CMD_SEND_ERROR; + + response[0] = AT91C_BASE_MCI->MCI_RSPR[0]; + response[1] = AT91C_BASE_MCI->MCI_RSPR[1]; + response[2] = AT91C_BASE_MCI->MCI_RSPR[2]; + response[3] = AT91C_BASE_MCI->MCI_RSPR[3]; + + return AT91C_CMD_SEND_OK; +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_SDCard_SetBusWidth +//* \brief Set bus width for SDCard +//*---------------------------------------------------------------------------- +int AT91F_MCI_SDCard_SetBusWidth(AT91PS_MciDevice pMCI_Device) +{ + volatile int ret_value; + char bus_width; + + do + { + ret_value =AT91F_MCI_GetStatus(pMCI_Device,pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address); + } + while((ret_value > 0) && ((ret_value & AT91C_SR_READY_FOR_DATA) == 0)); + + // Select Card + AT91F_MCI_SendCommand(pMCI_Device, + AT91C_SEL_DESEL_CARD_CMD, + (pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address)<<16); + + // Set bus width for Sdcard + if(pMCI_Device->pMCI_DeviceDesc->SDCard_bus_width == AT91C_MCI_SCDBUS) + bus_width = AT91C_BUS_WIDTH_4BITS; + else bus_width = AT91C_BUS_WIDTH_1BIT; + + if (AT91F_MCI_SDCard_SendAppCommand(pMCI_Device,AT91C_SDCARD_SET_BUS_WIDTH_CMD,bus_width) != AT91C_CMD_SEND_OK) + return AT91C_CMD_SEND_ERROR; + + return AT91C_CMD_SEND_OK; +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_SDCard_Init +//* \brief Return the SDCard initialisation status +//*---------------------------------------------------------------------------- +int AT91F_MCI_SDCard_Init (AT91PS_MciDevice pMCI_Device) +{ + unsigned int tab_response[4]; + unsigned int mult,blocknr; + + AT91F_MCI_SendCommand(pMCI_Device, AT91C_GO_IDLE_STATE_CMD, AT91C_NO_ARGUMENT); + + if(AT91F_MCI_SDCard_GetOCR(pMCI_Device) == AT91C_INIT_ERROR) + return AT91C_INIT_ERROR; + + if (AT91F_MCI_SDCard_GetCID(pMCI_Device,tab_response) == AT91C_CMD_SEND_OK) + { + pMCI_Device->pMCI_DeviceFeatures->Card_Inserted = AT91C_SD_CARD_INSERTED; + + if (AT91F_MCI_SendCommand(pMCI_Device, AT91C_SET_RELATIVE_ADDR_CMD, 0) == AT91C_CMD_SEND_OK) + { + pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address = (AT91C_BASE_MCI->MCI_RSPR[0] >> 16); + if (AT91F_MCI_GetCSD(pMCI_Device,pMCI_Device->pMCI_DeviceFeatures->Relative_Card_Address,tab_response) == AT91C_CMD_SEND_OK) + { + pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length = 1 << ((tab_response[1] >> AT91C_CSD_RD_B_LEN_S) & AT91C_CSD_RD_B_LEN_M ); + pMCI_Device->pMCI_DeviceFeatures->Max_Write_DataBlock_Length = 1 << ((tab_response[3] >> AT91C_CSD_WBLEN_S) & AT91C_CSD_WBLEN_M ); + pMCI_Device->pMCI_DeviceFeatures->Sector_Size = 1 + ((tab_response[2] >> AT91C_CSD_v21_SECT_SIZE_S) & AT91C_CSD_v21_SECT_SIZE_M ); + pMCI_Device->pMCI_DeviceFeatures->Read_Partial = (tab_response[1] >> AT91C_CSD_RD_B_PAR_S) & AT91C_CSD_RD_B_PAR_M; + pMCI_Device->pMCI_DeviceFeatures->Write_Partial = (tab_response[3] >> AT91C_CSD_WBLOCK_P_S) & AT91C_CSD_WBLOCK_P_M; + pMCI_Device->pMCI_DeviceFeatures->Erase_Block_Enable = (tab_response[3] >> AT91C_CSD_v21_ER_BLEN_EN_S) & AT91C_CSD_v21_ER_BLEN_EN_M; + pMCI_Device->pMCI_DeviceFeatures->Read_Block_Misalignment = (tab_response[1] >> AT91C_CSD_RD_B_MIS_S) & AT91C_CSD_RD_B_MIS_M; + pMCI_Device->pMCI_DeviceFeatures->Write_Block_Misalignment = (tab_response[1] >> AT91C_CSD_WR_B_MIS_S) & AT91C_CSD_WR_B_MIS_M; + + //// Compute Memory Capacity + // compute MULT + mult = 1 << ( ((tab_response[2] >> AT91C_CSD_C_SIZE_M_S) & AT91C_CSD_C_SIZE_M_M) + 2 ); + // compute MSB of C_SIZE + blocknr = ((tab_response[1] >> AT91C_CSD_CSIZE_H_S) & AT91C_CSD_CSIZE_H_M) << 2; + // compute MULT * (LSB of C-SIZE + MSB already computed + 1) = BLOCKNR + blocknr = mult * ( ( blocknr + ( (tab_response[2] >> AT91C_CSD_CSIZE_L_S) & AT91C_CSD_CSIZE_L_M) ) + 1 ); + + pMCI_Device->pMCI_DeviceFeatures->Memory_Capacity = pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length * blocknr; + //// End of Compute Memory Capacity + printf("SD-Card: %d Bytes\n\r", pMCI_Device->pMCI_DeviceFeatures->Memory_Capacity); + + if( AT91F_MCI_SDCard_SetBusWidth(pMCI_Device) == AT91C_CMD_SEND_OK ) + { + if (AT91F_MCI_SetBlocklength(pMCI_Device,pMCI_Device->pMCI_DeviceFeatures->Max_Read_DataBlock_Length) == AT91C_CMD_SEND_OK) + return AT91C_INIT_OK; + } + } + } + } + return AT91C_INIT_ERROR; +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_CfgDevice +//* \brief This function is used to initialise MMC or SDCard Features +//*---------------------------------------------------------------------------- +void AT91F_CfgDevice(void) +{ + // Init Device Structure + + MCI_Device_Features.Relative_Card_Address = 0; + MCI_Device_Features.Card_Inserted = AT91C_CARD_REMOVED; + MCI_Device_Features.Max_Read_DataBlock_Length = 0; + MCI_Device_Features.Max_Write_DataBlock_Length = 0; + MCI_Device_Features.Read_Partial = 0; + MCI_Device_Features.Write_Partial = 0; + MCI_Device_Features.Erase_Block_Enable = 0; + MCI_Device_Features.Sector_Size = 0; + MCI_Device_Features.Memory_Capacity = 0; + + MCI_Device_Desc.state = AT91C_MCI_IDLE; + MCI_Device_Desc.SDCard_bus_width = AT91C_MCI_SCDBUS; + + // Init AT91S_DataFlash Global Structure, by default AT45DB choosen !!! + MCI_Device.pMCI_DeviceDesc = &MCI_Device_Desc; + MCI_Device.pMCI_DeviceFeatures = &MCI_Device_Features; + +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCI_Init +//* \brief Initialsise Card +//*---------------------------------------------------------------------------- +int AT91F_MCI_Init(void) +{ + +/////////////////////////////////////////////////////////////////////////////////////////// +// MCI Init : common to MMC and SDCard +/////////////////////////////////////////////////////////////////////////////////////////// + + // Set up PIO SDC_TYPE to switch on MMC/SDCard and not DataFlash Card + AT91F_PIO_CfgOutput(AT91C_BASE_PIOB,AT91C_PIO_PB7); + AT91F_PIO_SetOutput(AT91C_BASE_PIOB,AT91C_PIO_PB7); + + // Init MCI for MMC and SDCard interface + AT91F_MCI_CfgPIO(); + AT91F_MCI_CfgPMC(); + AT91F_PDC_Open(AT91C_BASE_PDC_MCI); + + // Disable all the interrupts + AT91C_BASE_MCI->MCI_IDR = 0xFFFFFFFF; + + // Init MCI Device Structures + AT91F_CfgDevice(); + + // Configure MCI interrupt + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, + AT91C_ID_MCI, + AT91C_AIC_PRIOR_HIGHEST, + AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, + AT91F_ASM_MCI_Handler); + + // Enable MCI interrupt + AT91F_AIC_EnableIt(AT91C_BASE_AIC,AT91C_ID_MCI); + + // Enable Receiver + AT91F_US_EnableRx((AT91PS_USART) AT91C_BASE_DBGU); + + AT91F_MCI_Configure(AT91C_BASE_MCI, + AT91C_MCI_DTOR_1MEGA_CYCLES, + AT91C_MCI_MR_PDCMODE, // 15MHz for MCK = 60MHz (CLKDIV = 1) + AT91C_MCI_SDCARD_4BITS_SLOTA); + + if(AT91F_MCI_SDCard_Init(&MCI_Device) != AT91C_INIT_OK) + return FALSE; + else + return TRUE; + +} + +//*---------------------------------------------------------------------------- +//* \fn AT91F_MCIDeviceWaitReady +//* \brief Wait for MCI Device ready +//*---------------------------------------------------------------------------- +void AT91F_MCIDeviceWaitReady(unsigned int timeout) +{ + volatile int status; + + do + { + status = AT91C_BASE_MCI->MCI_SR; + timeout--; + } + while( !(status & AT91C_MCI_NOTBUSY) && (timeout>0) ); +} + +unsigned int swab32(unsigned int data) +{ + unsigned int res = 0; + + res = (data & 0x000000ff) << 24 | + (data & 0x0000ff00) << 8 | + (data & 0x00ff0000) >> 8 | + (data & 0xff000000) >> 24; + + return res; +} + +//*-------------------------------------------------------------------- +//* \fn AT91F_MCI_ReadBlockSwab +//* \brief Read Block and swap byte order +//*-------------------------------------------------------------------- +int AT91F_MCI_ReadBlockSwab( + AT91PS_MciDevice pMCI_Device, + int src, + unsigned int *databuffer, + int sizeToRead) +{ + int i; + unsigned char *buf = (unsigned char *)databuffer; + + //* Read Block 1 + for(i=0;i