📄 lh7a400_mmc_driver.c
字号:
INT_32 index;
response = (UNS_16 *) buf;
// Wait for response
while ((mmc_regs->mmc_status & MMC_END_CMD_RESP) == 0);
// Read the necessary number of response words from the response
// FIFO
for (index = 0; index < (resp_size / 2); index++)
{
// response [index] = swap (mmc_regs->result_fifo);
response [index] = mmc_regs->result_fifo;
}
}
/***********************************************************************
*
* Function: mmcif_init
*
* Purpose:
* Initialize the MMC interface.
*
* Processing:
* TBD
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* '1' if a MMC card has been detected, '0' otherwise.
*
* Notes:
* None
*
**********************************************************************/
INT_32 mmcif_init (void)
{
INT_32 card_inserted;
mmc_status_type cstatus;
INT_32 try_count, successful_init, ocr_attempts;
// Set register address for CPLD interface
cpld_boot_mmc_status = (UNS_32 *) CPLD_BOOTMMC_ST;
// Set mmc base address to point to MMC register set
mmc_regs = (MMCREGS *) MMC_BASE_ADDR;
// Check to see if card is inserted
card_inserted = mmcif_is_card_inserted ();
// Continue if a card is available
if (card_inserted == 1)
{
try_count = 1;
successful_init = 0;
while ((try_count > 0) && (successful_init == 0))
{
// Disable controller
mmc_regs->mmc_prediv = 0;
// Disable SPI mode control functions
mmc_regs->spi_mode = 0;
// Disable interrupts, polling mode only
mmc_regs->int_mask = -1;
// Enable the PCLK to the MMC, enable FIFO reads via APB,
// and set predivider to HCLK / 4
mmc_regs->mmc_prediv =
(MMC_EN | MMC_APB_RD_EN | MMC_PREDIV (6));
// Set the clock divider to the initialization clock value
// (With a prediv of HCLK / 4 and and clkdiv of 6
// (1/64 divider), the maximum bit speed (at 100MHz HCLK)
// will be 390KBps
mmc_regs->mmc_clk_rate = 6;
// Set timeout values for data and response
mmc_regs->response_to = 0xFF;
mmc_regs->read_to = 0x01FF;
// Disable the MMC clock
mmc_clock_stop ();
// Place card in idle mode
mmc_command (MMC_IDLE, 0);
// Poll card until it has completed the power-up sequence
ocr_attempts = 80;
ocr [0] = 0;
while (((ocr [0] & 0x80) == 0) && (ocr_attempts > 0))
{
mmc_command (MMC_SOP_COND, VRANGE_OCR);
mmc_get_response (&ocr, sizeof (ocr));
ocr_attempts--;
}
try_count--;
successful_init = (INT_32) ((ocr [0] & 0x80) != 0);
}
// Request the CID from the MMC card(s)
mmc_command (MMC_ALL_SEND_CID, 0);
mmc_get_response (&acid, sizeof (acid));
// Set the relative address of this card (only 1 card is
// presently supported)
rca = 0x00010000;
mmc_command (MMC_SRA, rca);
mmc_get_response (&cstatus, sizeof (cstatus));
// Use faster response timeout after init
mmc_regs->response_to = 0x10;
mmc_regs->mmc_prediv = (MMC_EN | MMC_APB_RD_EN | MMC_PREDIV (3));
mmc_regs->mmc_clk_rate = 1; // (100 / 6) Mbps max
// Select card 'rca' as the active card
mmc_command (MMC_DES_CARD, rca);
mmc_get_response (&cstatus, sizeof (cstatus));
// The CID and CSD are read (but never used)
mmc_command (MMC_SEND_CID, rca);
mmc_get_response (&cid, sizeof (cid));
mmc_command (MMC_SEND_CSD, rca);
mmc_get_response (&csd, sizeof (csd));
// Deselect card
mmc_command (MMC_DES_CARD, 0);
mmc_get_response (&cstatus, sizeof (cstatus));
// Leave the clock disabled until needed
mmc_clock_stop ();
}
return card_inserted;
}
/***********************************************************************
*
* Function: mmcif_shutdown
*
* Purpose:
* Shutdown the MMC interface.
*
* Processing:
* TBD
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* None
*
**********************************************************************/
void mmcif_shutdown (void)
{
mmc_status_type cstatus;
// Put the card in inactive state - normally this is not
// needed, but if this init sequence is called more than once,
// the second time will fail withou this sequence
mmc_command (MMC_INACTIVE, 0);
mmc_get_response (&cstatus, sizeof (cstatus));
// Disable the MMC clock
mmc_regs->str_stp_clk = MMC_STOP_CLK;
// Wait for clock to stop
while ((mmc_regs->mmc_status & MMC_CLK_ENABLE) == 0);
// Disable PCLK to the device
mmc_regs->mmc_prediv = mmc_regs->mmc_prediv & ~MMC_EN;
}
/***********************************************************************
*
* Function: mmcif_is_card_inserted
*
* Purpose:
* Determine if a card is inserted
*
* Processing:
* TBD
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* '1' if a card is inserted, '0' otherwise.
*
* Notes:
* None
*
**********************************************************************/
INT_32 mmcif_is_card_inserted (void)
{
return ((*cpld_boot_mmc_status & CPLD_MMC_DETECT) != 0);
}
/***********************************************************************
*
* Function: mmcif_set_sector
*
* Purpose:
* Set the sector number for the next operation.
*
* Processing:
* TBD
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* '1' if a card is inserted, '0' otherwise.
*
* Notes:
* The convention is Cylinder/Head/Sector (CHS). The function will
* convert the CHS values to a value that works with the MMC card.
*
**********************************************************************/
void mmcif_set_sector (UNS_32 sectorno)
{
next_sector = (UNS_32) sectorno * MMC_BLK_SIZE;
}
/***********************************************************************
*
* Function: mmcif_is_card_ready
*
* Purpose:
* Determines if the card is ready for a new command.
*
* Processing:
* Use the busy status function as the card ready indicator.
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* '1' if the card is ready for a new command, '0' otherwise.
*
* Notes:
* None
*
**********************************************************************/
INT_32 mmcif_is_card_ready (void)
{
return (1 - mmcif_is_card_busy ());
}
/***********************************************************************
*
* Function: mmcif_is_card_busy
*
* Purpose:
* Determine if a card is busy (processing a command).
*
* Processing:
* TBD
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* '1' if the card is busy, '0' otherwise.
*
* Notes:
* This function is not used. (Specific waits are performed in other
* placeds in the driver.)
*
**********************************************************************/
INT_32 mmcif_is_card_busy (void)
{
return 0;
}
/***********************************************************************
*
* Function: mmcif_start_sector_read
*
* Purpose:
* Starts the read of a sector.
*
* Processing:
* TBD
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* None
*
**********************************************************************/
void mmcif_start_sector_read (void)
{
mmc_status_type cstatus;
UNS_16 dummy;
// Select card 'rca' as the active card
mmc_command (MMC_DES_CARD, rca);
mmc_get_response (&cstatus, sizeof (cstatus));
// Send block length command to card
mmc_command (MMC_SET_BLEN, MMC_BLK_SIZE);
mmc_get_response (&cstatus, sizeof (cstatus));
// Pre-empty the data FIFO
while ((mmc_regs->mmc_status & MMC_FIFO_EMPTY) == 0)
{
dummy = mmc_regs->data_fifo;
}
// Issue the read block command
mmc_command (MMC_READ_SINGLE, next_sector);
mmc_get_response (&cstatus, sizeof (cstatus));
}
/***********************************************************************
*
* Function: mmcif_start_sector_write
*
* Purpose:
* Starts the write of a sector.
*
* Processing:
* TBD
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* None
*
**********************************************************************/
void mmcif_start_sector_write (void)
{
mmc_status_type cstatus;
UNS_16 dummy;
#if 0
// Select card 'rca' as the active card
mmc_command (MMC_DES_CARD, rca);
mmc_get_response (&cstatus, MMC_DES_CARD);
// Send block length command to card
mmc_command (MMC_SET_BLEN, MMC_BLK_SIZE);
mmc_get_response (&cstatus, MMC_SET_BLEN);
// Pre-empty the data FIFO
while ((mmc_regs->mmc_status & MMC_FIFO_EMPTY) == 0)
{
dummy = mmc_regs->data_fifo;
}
// Issue the read block command
mmc_command (MMC_WRITE_SINGLE, next_sector);
mmc_get_response (&cstatus, MMC_WRITE_SINGLE);
#endif
}
/***********************************************************************
*
* Function: mmcif_read_data
*
* Purpose:
* Read a block of data from the MMC card.
*
* Processing:
* TBD
*
* Parameters:
* data : Pointer to where to put read data from the MMC card
* bytes : Number of bytes to read
*
* Outputs:
* The data pointed to by data will be updated.
*
* Returns:
* The number of bytes read from the card.
*
* Notes:
* None
*
**********************************************************************/
INT_32 mmcif_read_data (void *data, INT_32 bytes)
{
INT_32 i = 0;
mmc_status_type cstatus;
UNS_16 *buf = (UNS_16 *) data;
// Wait until transfer is complete
while ((mmc_regs->mmc_status & MMC_DATA_TRAN_DONE) == 0);
// Continue reading data until FIFO is empty
while (((mmc_regs->mmc_status & MMC_FIFO_EMPTY) == 0) &&
(i < (bytes / 2)))
{
// Any data in the FIFO
if ((mmc_regs->mmc_status & MMC_FIFO_EMPTY) == 0)
{
buf [i] = swap (mmc_regs->data_fifo);
i++;
}
}
// Stop the MMC clock
mmc_clock_stop ();
// Set card 'rca' as an inactive card
mmc_command (MMC_DES_CARD, 0);
mmc_get_response (&cstatus, sizeof (cstatus));
return bytes;
}
/***********************************************************************
*
* Function: mmcif_write_data
*
* Purpose:
* Write a block of data to the MMC card.
*
* Processing:
* TBD
*
* Parameters:
* data : Pointer to where to get data to write to the MMC card
* bytes : Number of bytes to write
*
* Outputs:
* None
*
* Returns:
* The number of bytes written from the card.
*
* Notes:
* None
*
**********************************************************************/
INT_32 mmcif_write_data (void *data, INT_32 bytes)
{
INT_32 i = 0;
mmc_status_type cstatus;
UNS_16 *buf = (UNS_16 *) data;
;
// Stop the MMC clock
mmc_clock_stop ();
// Set card 'rca' as an inactive card
mmc_command (MMC_DES_CARD, 0);
mmc_get_response (&cstatus, sizeof (cstatus));
return bytes;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -