| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744 |
- //*****************************************************************************
- //
- // sdhost.c
- //
- // Driver for the SD Host (SDHost) Interface
- //
- // Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
- //
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions
- // are met:
- //
- // Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- //
- // Redistributions in binary form must reproduce the above copyright
- // notice, this list of conditions and the following disclaimer in the
- // documentation and/or other materials provided with the
- // distribution.
- //
- // Neither the name of Texas Instruments Incorporated nor the names of
- // its contributors may be used to endorse or promote products derived
- // from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- //
- //*****************************************************************************
- //*****************************************************************************
- //
- //! \addtogroup Secure_Digital_Host_api
- //! @{
- //
- //*****************************************************************************
- #include "inc/hw_types.h"
- #include "inc/hw_memmap.h"
- #include "inc/hw_mmchs.h"
- #include "inc/hw_ints.h"
- #include "inc/hw_apps_config.h"
- #include "interrupt.h"
- #include "sdhost.h"
- //*****************************************************************************
- //
- //! Configures SDHost module.
- //!
- //! \param ulBase is the base address of SDHost module.
- //!
- //! This function configures the SDHost module, enabling internal sub-modules.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostInit(unsigned long ulBase)
- {
- //
- // Assert module reset
- //
- HWREG(ulBase + MMCHS_O_SYSCONFIG) = 0x2;
- //
- // Wait for soft reset to complete
- //
- while( !(HWREG(ulBase + MMCHS_O_SYSCONFIG) & 0x1) )
- {
- }
- //
- // Assert internal reset
- //
- HWREG(ulBase + MMCHS_O_SYSCTL) |= (1 << 24);
- //
- // Wait for Reset to complete
- //
- while( (HWREG(ulBase + MMCHS_O_SYSCTL) & (0x1 << 24)) )
- {
- }
- //
- // Set capability register, 1.8 and 3.0 V
- //
- HWREG(ulBase + MMCHS_O_CAPA) = (0x7 <<24);
- //
- // Select bus voltage, 3.0 V
- //
- HWREG(ulBase + MMCHS_O_HCTL) |= 0x7 << 9;
- //
- // Power up the bus
- //
- HWREG(ulBase + MMCHS_O_HCTL) |= 1 << 8;
- //
- // Wait for power on
- //
- while( !(HWREG(ulBase + MMCHS_O_HCTL) & (1<<8)) )
- {
- }
- HWREG(ulBase + MMCHS_O_CON) |= 1 << 21;
- //
- // Un-mask all events
- //
- HWREG(ulBase + MMCHS_O_IE) = 0xFFFFFFFF;
- }
- //*****************************************************************************
- //
- //! Resets SDHost command line
- //!
- //! \param ulBase is the base address of SDHost module.
- //!
- //! This function assers a soft reset for the command line
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostCmdReset(unsigned long ulBase)
- {
- HWREG(ulBase + MMCHS_O_SYSCTL) |= 1 << 25;
- while( (HWREG(ulBase + MMCHS_O_SYSCTL) & (1 << 25)) )
- {
- }
- }
- //*****************************************************************************
- //
- //! Sends command over SDHost interface
- //!
- //! \param ulBase is the base address of SDHost module.
- //! \param ulCmd is the command to send.
- //! \param ulArg is the argument for the command.
- //!
- //! This function send command to the attached card over the SDHost interface.
- //!
- //! The \e ulCmd parameter can be one of \b SDHOST_CMD_0 to \b SDHOST_CMD_63.
- //! It can be logically ORed with one or more of the following:
- //! - \b SDHOST_MULTI_BLK for multi-block transfer
- //! - \b SDHOST_WR_CMD if command is followed by write data
- //! - \b SDHOST_RD_CMD if command is followed by read data
- //! - \b SDHOST_DMA_EN if SDHost need to generate DMA request.
- //! - \b SDHOST_RESP_LEN_136 if 136 bit response is expected
- //! - \b SDHOST_RESP_LEN_48 if 48 bit response is expected
- //! - \b SDHOST_RESP_LEN_48B if 48 bit response with busy bit is expected
- //!
- //! The parameter \e ulArg is the argument for the command
- //!
- //! \return Returns 0 on success, -1 otherwise.
- //
- //*****************************************************************************
- long
- SDHostCmdSend(unsigned long ulBase, unsigned long ulCmd, unsigned ulArg)
- {
- //
- // Set Data Timeout
- //
- HWREG(ulBase + MMCHS_O_SYSCTL) |= 0x000E0000;
- //
- // Check for cmd inhabit
- //
- if( (HWREG(ulBase + MMCHS_O_PSTATE) & 0x1))
- {
- return -1;
- }
- //
- // Set the argument
- //
- HWREG(ulBase + MMCHS_O_ARG) = ulArg;
- //
- // Send the command
- //
- HWREG(ulBase + MMCHS_O_CMD) = ulCmd;
- return 0;
- }
- //*****************************************************************************
- //
- //! Writes a data word into the SDHost write buffer.
- //!
- //! \param ulBase is the base address of SDHost module.
- //! \param ulData is data word to be transfered.
- //!
- //! This function writes a single data word into the SDHost write buffer. The
- //! function returns \b true if there was a space available in the buffer else
- //! returns \b false.
- //!
- //! \return Return \b true on success, \b false otherwise.
- //
- //*****************************************************************************
- tBoolean
- SDHostDataNonBlockingWrite(unsigned long ulBase, unsigned long ulData)
- {
- //
- // See if there is a space in the write buffer
- //
- if( (HWREG(ulBase + MMCHS_O_PSTATE) & (1<<10)) )
- {
- //
- // Write the data into the buffer
- //
- HWREG(ulBase + MMCHS_O_DATA) = ulData;
- //
- // Success.
- //
- return(true);
- }
- else
- {
- //
- // No free sapce, failure.
- //
- return(false);
- }
- }
- //*****************************************************************************
- //
- //! Waits to write a data word into the SDHost write buffer.
- //!
- //! \param ulBase is the base address of SDHost module.
- //! \param ulData is data word to be transfered.
- //!
- //! This function writes \e ulData into the SDHost write buffer. If there is no
- //! space in the write buffer this function waits until there is a space
- //! available before returning.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostDataWrite(unsigned long ulBase, unsigned long ulData)
- {
- //
- // Wait until space is available
- //
- while( !(HWREG(ulBase + MMCHS_O_PSTATE) & (1<<10)) )
- {
- }
- //
- // Write the data
- //
- HWREG(ulBase + MMCHS_O_DATA) = ulData;
- }
- //*****************************************************************************
- //
- //! Waits for a data word from the SDHost read buffer
- //!
- //! \param ulBase is the base address of SDHost module.
- //! \param pulData is pointer to read data variable.
- //!
- //! This function reads a single data word from the SDHost read buffer. If there
- //! is no data available in the buffer the function will wait until a data
- //! word is received before returning.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostDataRead(unsigned long ulBase, unsigned long *pulData)
- {
- //
- // Wait until data is available
- //
- while( !(HWREG(ulBase + MMCHS_O_PSTATE) & (1<<11)) )
- {
- }
- //
- // Read the data
- //
- *pulData = HWREG(ulBase + MMCHS_O_DATA);
- }
- //*****************************************************************************
- //
- //! Reads single data word from the SDHost read buffer
- //!
- //! \param ulBase is the base address of SDHost module.
- //! \param pulData is pointer to read data variable.
- //!
- //! This function reads a data word from the SDHost read buffer. The
- //! function returns \b true if there was data available in to buffer else
- //! returns \b false.
- //!
- //! \return Return \b true on success, \b false otherwise.
- //
- //*****************************************************************************
- tBoolean
- SDHostDataNonBlockingRead(unsigned long ulBase, unsigned long *pulData)
- {
- //
- // See if there is any data in the read buffer.
- //
- if( (HWREG(ulBase + MMCHS_O_PSTATE) & (1<11)) )
- {
- //
- // Read the data word.
- //
- *pulData = HWREG(ulBase + MMCHS_O_DATA);
- //
- // Success
- //
- return(true);
- }
- else
- {
- //
- // No data available, failure.
- //
- return(false);
- }
- }
- //*****************************************************************************
- //
- //! Registers the interrupt handler for SDHost interrupt
- //!
- //! \param ulBase is the base address of SDHost module
- //! \param pfnHandler is a pointer to the function to be called when the
- //! SDHost interrupt occurs.
- //!
- //! This function does the actual registering of the interrupt handler. This
- //! function enables the global interrupt in the interrupt controller; specific
- //! SDHost interrupts must be enabled via SDHostIntEnable(). It is the
- //! interrupt handler's responsibility to clear the interrupt source.
- //!
- //! \sa IntRegister() for important information about registering interrupt
- //! handlers.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostIntRegister(unsigned long ulBase, void (*pfnHandler)(void))
- {
- //
- // Register the interrupt handler.
- //
- IntRegister(INT_MMCHS, pfnHandler);
- //
- // Enable the SDHost interrupt.
- //
- IntEnable(INT_MMCHS);
- }
- //*****************************************************************************
- //
- //! Unregisters the interrupt handler for SDHost interrupt
- //!
- //! \param ulBase is the base address of SDHost module
- //!
- //! This function does the actual unregistering of the interrupt handler. It
- //! clears the handler to be called when a SDHost interrupt occurs. This
- //! function also masks off the interrupt in the interrupt controller so that
- //! the interrupt handler no longer is called.
- //!
- //! \sa IntRegister() for important information about registering interrupt
- //! handlers.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostIntUnregister(unsigned long ulBase)
- {
- //
- // Disable the SDHost interrupt.
- //
- IntDisable(INT_MMCHS);
- //
- // Unregister the interrupt handler.
- //
- IntUnregister(INT_MMCHS);
- }
- //*****************************************************************************
- //
- //! Enable individual interrupt source for the specified SDHost
- //!
- //! \param ulBase is the base address of SDHost module.
- //! \param ulIntFlags is a bit mask of the interrupt sources to be enabled.
- //!
- //! This function enables the indicated SDHost interrupt sources. Only the
- //! sources that are enabled can be reflected to the processor interrupt;
- //! disabled sources have no effect on the processor.
- //!
- //! The \e ulIntFlags parameter is the logical OR of any of the following:
- //! - \b SDHOST_INT_CC Command Complete interrupt
- //! - \b SDHOST_INT_TC Transfer Complete interrupt
- //! - \b SDHOST_INT_BWR Buffer Write Ready interrupt
- //! - \b SDHOST_INT_BRR Buffer Read Ready interrupt
- //! - \b SDHOST_INT_ERRI Error interrupt
- //! - \b SDHOST_INT_CTO Command Timeout error interrupt
- //! - \b SDHOST_INT_CEB Command End Bit error interrupt
- //! - \b SDHOST_INT_DTO Data Timeout error interrupt
- //! - \b SDHOST_INT_DCRC Data CRC error interrupt
- //! - \b SDHOST_INT_DEB Data End Bit error
- //! - \b SDHOST_INT_CERR Cart Status Error interrupt
- //! - \b SDHOST_INT_BADA Bad Data error interrupt
- //! - \b SDHOST_INT_DMARD Read DMA done interrupt
- //! - \b SDHOST_INT_DMAWR Write DMA done interrupt
- //!
- //! Note that SDHOST_INT_ERRI can only be used with \sa SDHostIntStatus()
- //! and is internally logical OR of all error status bits. Setting this bit
- //! alone as \e ulIntFlags doesn't generates any interrupt.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostIntEnable(unsigned long ulBase,unsigned long ulIntFlags)
- {
- //
- // Enable DMA done interrupts
- //
- HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR) =
- (ulIntFlags >> 30);
- //
- // Enable the individual interrupt sources
- //
- HWREG(ulBase + MMCHS_O_ISE) |= (ulIntFlags & 0x3FFFFFFF);
- }
- //*****************************************************************************
- //
- //! Enable individual interrupt source for the specified SDHost
- //!
- //! \param ulBase is the base address of SDHost module.
- //! \param ulIntFlags is a bit mask of the interrupt sources to be enabled.
- //!
- //! This function disables the indicated SDHost interrupt sources. Only the
- //! sources that are enabled can be reflected to the processor interrupt;
- //! disabled sources have no effect on the processor.
- //!
- //! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags
- //! parameter to SDHostIntEnable().
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostIntDisable(unsigned long ulBase,unsigned long ulIntFlags)
- {
- //
- // Disable DMA done interrupts
- //
- HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) =
- (ulIntFlags >> 30);
- //
- // Disable the individual interrupt sources
- //
- HWREG(ulBase + MMCHS_O_ISE) &= ~(ulIntFlags & 0x3FFFFFFF);
- }
- //*****************************************************************************
- //
- //! Gets the current interrupt status.
- //!
- //! \param ulBase is the base address of SDHost module.
- //!
- //! This function returns the interrupt status for the specified SDHost.
- //!
- //! \return Returns the current interrupt status, enumerated as a bit field of
- //! values described in SDHostIntEnable().
- //
- //*****************************************************************************
- unsigned long
- SDHostIntStatus(unsigned long ulBase)
- {
- unsigned long ulIntStatus;
- //
- // Get DMA done interrupt status
- //
- ulIntStatus = HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_RAW);
- ulIntStatus = (ulIntStatus << 30);
- //
- // Return the status of individual interrupt sources
- //
- ulIntStatus |= (HWREG(ulBase + MMCHS_O_STAT) & 0x3FFFFFFF);
- return(ulIntStatus);
- }
- //*****************************************************************************
- //
- //! Clears the individual interrupt sources.
- //!
- //! \param ulBase is the base address of SDHost module.
- //! \param ulIntFlags is a bit mask of the interrupt sources to be cleared.
- //!
- //! The specified SDHost interrupt sources are cleared, so that they no longer
- //! assert. This function must be called in the interrupt handler to keep the
- //! interrupt from being recognized again immediately upon exit.
- //!
- //! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags
- //! parameter to SDHostIntEnable().
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostIntClear(unsigned long ulBase,unsigned long ulIntFlags)
- {
- //
- // Clear DMA done interrupts
- //
- HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) =
- (ulIntFlags >> 30);
- //
- // Clear the individual interrupt sources
- //
- HWREG(ulBase + MMCHS_O_STAT) = (ulIntFlags & 0x3FFFFFFF);
- }
- //*****************************************************************************
- //
- //! Sets the card status error mask.
- //!
- //! \param ulBase is the base address of SDHost module
- //! \param ulErrMask is the bit mask of card status errors to be enabled
- //!
- //! This function sets the card status error mask for response type R1, R1b,
- //! R5, R5b and R6 response. The parameter \e ulErrMask is the bit mask of card
- //! status errors to be enabled, if the corresponding bits in the 'card status'
- //! field of a respose are set then the host controller indicates a card error
- //! interrupt status. Only bits referenced as type E (error) in status field in
- //! the response can set a card status error.
- //!
- //! \return None
- //
- //*****************************************************************************
- void
- SDHostCardErrorMaskSet(unsigned long ulBase, unsigned long ulErrMask)
- {
- //
- // Set the card status error mask
- //
- HWREG(ulBase + MMCHS_O_CSRE) = ulErrMask;
- }
- //*****************************************************************************
- //
- //! Gets the card status error mask.
- //!
- //! \param ulBase is the base address of SDHost module
- //!
- //! This function gets the card status error mask for response type R1, R1b,
- //! R5, R5b and R6 response.
- //!
- //! \return Returns the current card status error.
- //
- //*****************************************************************************
- unsigned long
- SDHostCardErrorMaskGet(unsigned long ulBase)
- {
- //
- // Return the card status error mask
- //
- return(HWREG(ulBase + MMCHS_O_CSRE));
- }
- //*****************************************************************************
- //
- //! Sets the SD Card clock.
- //!
- //! \param ulBase is the base address of SDHost module
- //! \param ulSDHostClk is the rate of clock supplied to SDHost module
- //! \param ulCardClk is the required SD interface clock
- //!
- //! This function configures the SDHost interface to supply the specified clock
- //! to the connected card.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostSetExpClk(unsigned long ulBase, unsigned long ulSDHostClk,
- unsigned long ulCardClk)
- {
- unsigned long ulDiv;
- //
- // Disable card clock
- //
- HWREG(ulBase + MMCHS_O_SYSCTL) &= ~0x4;
- //
- // Enable internal clock
- //
- HWREG(ulBase + MMCHS_O_SYSCTL) |= 0x1;
- ulDiv = ((ulSDHostClk/ulCardClk) & 0x3FF);
- //
- // Set clock divider,
- //
- HWREG(ulBase + MMCHS_O_SYSCTL) = ((HWREG(ulBase + MMCHS_O_SYSCTL) &
- ~0x0000FFC0)| (ulDiv) << 6);
- //
- // Wait for clock to stablize
- //
- while( !(HWREG(ulBase + MMCHS_O_SYSCTL) & 0x2) )
- {
- }
- //
- // Enable card clock
- //
- HWREG(ulBase + MMCHS_O_SYSCTL) |= 0x4;
- }
- //*****************************************************************************
- //
- //! Get the response for the last command.
- //!
- //! \param ulBase is the base address of SDHost module
- //! \param ulRespnse is 128-bit response.
- //!
- //! This function gets the response from the SD card for the last command
- //! send.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostRespGet(unsigned long ulBase, unsigned long ulRespnse[4])
- {
- //
- // Read the responses.
- //
- ulRespnse[0] = HWREG(ulBase + MMCHS_O_RSP10);
- ulRespnse[1] = HWREG(ulBase + MMCHS_O_RSP32);
- ulRespnse[2] = HWREG(ulBase + MMCHS_O_RSP54);
- ulRespnse[3] = HWREG(ulBase + MMCHS_O_RSP76);
- }
- //*****************************************************************************
- //
- //! Set the block size for data transfer
- //!
- //! \param ulBase is the base address of SDHost module
- //! \param ulBlkSize is the transfer block size in bytes
- //!
- //! This function sets the block size the data transfer.
- //!
- //! The parameter \e ulBlkSize is size of each data block in bytes.
- //! This should be in range 0 - 2^10.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostBlockSizeSet(unsigned long ulBase, unsigned short ulBlkSize)
- {
- //
- // Set the block size
- //
- HWREG(ulBase + MMCHS_O_BLK) = ((HWREG(ulBase + MMCHS_O_BLK) & 0x00000FFF)|
- (ulBlkSize & 0xFFF));
- }
- //*****************************************************************************
- //
- //! Set the block size and count for data transfer
- //!
- //! \param ulBase is the base address of SDHost module
- //! \param ulBlkCount is the number of blocks
- //!
- //! This function sets block count for the data transfer. This needs to be set
- //! for each block transfer. \sa SDHostBlockSizeSet()
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- SDHostBlockCountSet(unsigned long ulBase, unsigned short ulBlkCount)
- {
- unsigned long ulRegVal;
- //
- // Read the current value
- //
- ulRegVal = HWREG(ulBase + MMCHS_O_BLK);
- //
- // Set the number of blocks
- //
- HWREG(ulBase + MMCHS_O_BLK) = ((ulRegVal & 0x0000FFFF)|
- (ulBlkCount << 16));
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
|