/***********************************************************************
* $Workfile: LH7A400_mmc_driver.c $
* $Revision: 1.6 $
* $Author: WellsK $
* $Date: Mar 17 2003 12:06:12 $
*
* Project: Basic Multimedia controller interface driver
*
* Description:
* This driver reads and writes raw 'sectors' in the MMC card via
* the Logical Block addressing (LBA) mechanism. Support functions for
* initializing and locating the card are available. All bookkeeping
* functions related to supporting the MMC interface must be performed
* at a higher driver level. Multitasking in the MMC interface is not
* supported. If a read operation is performed, the data should be
* read from the card before another operation is performed.
*
* Notes:
* The MMC card detection logic can be performed via the function
* supplied in the CPLD driver. To reduce dependency on that driver,
* the function has been added in this driver.
* MMC clock speed scales with bus speed and is presently locked to
* bus speed / 6. At 100MHz, the MMC clock speed is 16.67Mbps.
*
* Revision History:
* $Log: //smaicnt2/pvcs/VM/CHIPS/archives/LH7A400/MMC/Drivers/LH7A400_mmc_driver.c-arc $
*
* Rev 1.6 Mar 17 2003 12:06:12 WellsK
* Corrected MMC init sequence. Many minor tweaks and
* adjustments. Updated ad corrected comments.
*
* Rev 1.5 Feb 19 2003 18:39:00 BarnettH
* Replaced Revision History elements which had been deleted.
* Used LH7A400_evb.h
* Revised manifest constant names throughout to agree with revised LH7A400_mmc.h
* Revised register structure member references throughout to agree with revised LH7A400_mmc.h
*
* Rev 1.4 Feb 06 2003 11:52:32 LeeLen
* Completed mmcif_start_sector_write() and mmcif_write_data() to support data writes to MMC
*
* Rev 1.3 Sep 22 2002 14:21:40 WellsK
* Remove call to shutdown if MMC card was not detected.
*
* Rev 1.2 Sep 14 2002 08:52:34 WellsK
* Corrected OCR check logic
* Corrected card select/deselect logic
* Used types and defines from MMC structure header file
* Other minor tweaks
*
* Rev 1.1 Sep 07 2002 12:05:40 WellsK
* Changed HCLK rate retrieve function. Added code to perform
* init with 4 retries before driver init fails.
*
* Rev 1.0 Aug 28 2002 13:51:08 WellsK
* Initial revision.
*
*
* SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
* OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
* AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES,
* SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
*
* SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY
* FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A
* SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
* FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
*
* COPYRIGHT (C) 2003 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
* CAMAS, WA
**********************************************************************/
#include "LH7A400_evb.h"
#include "LH7A400_mmc_driver.h"
#include "LH7A400_CSC_driver.h"
//**********************************************************************
// Local defines
//**********************************************************************
// CPLD register bits and addresses
#define CPLD_BOOTMMC_ST 0x20000006 // Boot/MMC status register address
#define CPLD_MMC_DETECT 0x0001 // CPLD MMC card detect
// Other defines
#define MMC_BPS_CLK 20000000 // Best MMC bit/second rate
#define MMC_BASE_ADDR 0x80000100 // MMC register set base
#define VRANGE_OCR 0x001C0000 // MMC cards allowed at 3.0 to 3.3v
#define MMC_BLK_SIZE 512 // MMC sector size
#define OCR_RDY_MASK 0x0080 // Mask to check OCR ready bit
#define MAX_OCR_RET 80 // Maximum OCR request retries
//**********************************************************************
// MMC structures
//**********************************************************************
// Possible commands (send operations are 'sent' from the card to the
// MultiMedia Controller (MMC)
typedef enum
{
MMC_IDLE, // Put card in idle mode
MMC_SOP_COND, // Send operating condition (OCR)
MMC_ALL_SEND_CID, // All send CID data
MMC_SRA, // Set relative address
MMC_DES_CARD, // Delselect card
MMC_SEND_CSD, // Send CSD data
MMC_SEND_CID, // Send CID register data (with rel. addr)
MMC_READ_UNTIL_STOP, // Read data until stop command
MMC_STOP_TRAN, // Stop data transfer
MMC_SSTAT, // Send status
MMC_INACTIVE, // Put card in inactive state
MMC_SET_BLEN, // Set block transfer length
MMC_READ_SINGLE, // Read a single block
MMC_READ_MULTIPLE, // Read multiple blocks
MMC_WRITE_SINGLE, // Write a single block
MMC_WRITE_MULTIPLE, // Write multiple blocks
MMC_INVALID_CMD // Invalid command
} mmc_command_type;
// Each command enumeration has a MMC command number (used by the card)
// and a MMC command/control word (used by the controller). This
// structure defines this word pair.
typedef struct
{
UNS_32 cmd;
UNS_32 cmdctl;
} cmd_ctrl_type;
//**********************************************************************
// MMC structured data returned from card commands (responses)
// These structures are not used in the code, but are placed here for
// informational purposes only.
//**********************************************************************
// OCR register data (response R1)
typedef struct
{
UNS_32 end_bit : 1;
UNS_32 crc7 : 7;
UNS_32 rsv1 : 8;
UNS_32 volts_20__21 : 1;
UNS_32 volts_21__22 : 1;
UNS_32 volts_22__23 : 1;
UNS_32 volts_23__24 : 1;
UNS_32 volts_24__25 : 1;
UNS_32 volts_25__26 : 1;
UNS_32 volts_26__27 : 1;
UNS_32 volts_27__28 : 1;
UNS_32 volts_28__29 : 1;
UNS_32 volts_29__30 : 1;
UNS_32 volts_30__31 : 1;
UNS_32 volts_31__32 : 1;
UNS_32 volts_32__33 : 1;
UNS_32 volts_33__34 : 1;
UNS_32 volts_34__35 : 1;
UNS_32 volts_35__36 : 1;
UNS_32 rsv2 : 7;
UNS_32 card_not_busy : 1;
UNS_32 cmd_index : 6;
UNS_32 start_tran_bits : 2;
} ocr_register_type;
// CID register data (not used, information only), 128 bits
typedef struct
{
UNS_32 rsv : 1;
UNS_32 crc : 7;
UNS_32 date : 8;
UNS_32 serial_number : 32;
UNS_32 product_rev : 8;
UNS_32 product_name_b : 32;
UNS_32 product_name_a : 16;
UNS_32 oem_id : 16;
UNS_32 manufacturer_id : 8;
} mmc_cid_type;
// CSD register data (not used, information only)
typedef struct
{
UNS_32 end_bit : 1;
UNS_32 crc7 : 7;
UNS_32 rsv1 : 1;
UNS_32 crc : 7;
UNS_32 ecc : 2;
UNS_32 rsv2 : 2;
UNS_32 wr_protect_tmp : 1;
UNS_32 wr_protect_perm : 1;
UNS_32 copy : 1;
UNS_32 rsv3 : 6;
UNS_32 wr_blk_partial : 1;
UNS_32 wr_blk_len : 4;
UNS_32 r2w_factor : 3;
UNS_32 default_ecc : 2;
UNS_32 wp_grp_enable : 1;
UNS_32 wp_grp_size : 5;
UNS_32 erase_grp_size : 5;
UNS_32 sector_size : 5;
UNS_32 c_size_mult : 3;
UNS_32 wr_curr_max : 3;
UNS_32 wr_curr_min : 3;
UNS_32 rd_curr_max : 3;
UNS_32 rd_curr_min : 3;
UNS_32 c_size_h : 2;
UNS_32 c_size_l : 10;
UNS_32 rsv4 : 2;
UNS_32 dsr_imp : 1;
UNS_32 rd_blk_misalgn : 1;
UNS_32 wr_blk_misalgn : 1;
UNS_32 rd_blk_partial : 1;
UNS_32 rd_blk_len : 4;
UNS_32 ccc : 12;
UNS_32 tran_speed : 8;
UNS_32 nsac : 8;
UNS_32 taac : 8;
UNS_32 rsv5 : 2;
UNS_32 mmc_prot : 4;
UNS_32 csd_struct : 2;
UNS_32 cmd_index : 6;
UNS_32 start_tran_bits : 2;
} mmc_csd_type;
// Status register data
typedef struct
{
UNS_32 rsv1 : 5;
UNS_32 app_cmd : 1;
UNS_32 rsv2 : 2;
UNS_32 buff_empty : 1;
UNS_32 card_state : 4;
UNS_32 erase_reset : 1;
UNS_32 card_ecc_dis : 1;
UNS_32 wp_erase_skip : 1;
UNS_32 csd_overwrite : 1;
UNS_32 int_error : 1;
UNS_32 overrun : 1;
UNS_32 underrun : 1;
UNS_32 general_error : 1;
UNS_32 cc_error : 1;
UNS_32 card_ecc_failed : 1;
UNS_32 illegal_cmd : 1;
UNS_32 crc_error : 1;
UNS_32 lock_ulock_fail : 1;
UNS_32 card_locked : 1;
UNS_32 wr_volation : 1;
UNS_32 erase_sel_error : 1;
UNS_32 erase_seq_error : 1;
UNS_32 invalid_blk_len : 1;
UNS_32 misalgn_addr : 1;
UNS_32 cmd_out_of_rnge : 1;
} mmc_status_type;
//**********************************************************************
// Package data
//**********************************************************************
// MMC register set base addresses
MMCREGS *mmc_regs;
// CPLD MMC status register
volatile UNS_32 *cpld_boot_mmc_status;
// Card identifier number (128 bits)
UNS_32 cid [5], acid [5];
// Card-specific data register (128 bits)
UNS_32 csd [5];
// Relative card address
UNS_32 rca;
// OCR register status
//ocr_register_type ocr;
UNS_16 ocr [3];
// Next sector operation pointer
UNS_32 next_sector;
// The following list maps a command enumeration to a MMC command
// number and command/control word
cmd_ctrl_type const cmd_data [MMC_INVALID_CMD] =
{
{0, (MMC_CMD_INITIALIZE | MMC_CMD_RESPONSE_FORMAT (0))}, // MMC_IDLE
{1, (MMC_CMD_RESPONSE_FORMAT (3))}, // MMC_SOP
{2, (MMC_CMD_RESPONSE_FORMAT (2))}, // MMC_ALL_SEND_CID
{3, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_SRA
{7, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_DES_CARD
{9, (MMC_CMD_RESPONSE_FORMAT (2))}, // MMC_SCSD
{10, (MMC_CMD_RESPONSE_FORMAT (2))}, // MMC_SCID
{11, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_READ_UNTIL_STOP
{12, (MMC_CMD_BUSY | MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_STOP_TRAN
{13, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_SSTAT
{15, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_INACTIVE
{16, (MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_SET_BLEN
{17, (MMC_CMD_DATA_EN | MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_READ_SINGLE
{18, (MMC_CMD_DATA_EN | MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_READ_MULTIPLE
{24, (MMC_CMD_BUSY | MMC_CMD_WRITE | MMC_CMD_DATA_EN | MMC_CMD_RESPONSE_FORMAT (1))}, // MMC_WRITE_SINGLE
{25, (MMC_CMD_BUSY | MMC_CMD_WRITE | MMC_CMD_DATA_EN | MMC_CMD_RESPONSE_FORMAT (1))} // MMC_WRITE_MULTIPLE
};
/***********************************************************************
*
* Function: mmcif_data_swap
*
* Purpose:
* Swaps the low and high bytes of the MMC data. This function may not
* be needed by the MMC driver, and is based on whether the higher
* level code passes the code down pre-swaped.
*
* Processing:
* See function.
*
* Parameters:
* val : Value to swap
*
* Outputs:
* None
*
* Returns:
* THe byte swapped value of 'val'.
*
* Notes:
* This function is private to this module.
*
**********************************************************************/
UNS_16 mmcif_data_swap (UNS_16 val)
{
UNS_16 hi, lo;
hi = ((UNS_16) val & 0x00FF) << 8;
lo = ((UNS_16) val & 0xFF00) >> 8;
return (lo + hi);
}
/***********************************************************************
*
* Function: mmc_clock_stop
*
* Purpose:
* Stops the MMC clock.
*
* Processing:
* See function.
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* This function is private to this module.
*
**********************************************************************/
void mmc_clock_stop (void)
{
// Stop the clock
mmc_regs->clock_control = MMC_STOP_CLOCK;
// Wait for MMC clock to stop
while ((mmc_regs->status & MMC_STATUS_CLOCK_ENABLED) == 0);
}
/***********************************************************************
*
* Function: mmc_clock_start
*
* Purpose:
* Starts the MMC clock.
*
* Processing:
* See function.
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* This function is private to this module.
*
**********************************************************************/
void mmc_clock_start (void)
{
// Stop the clock
mmc_regs->clock_control = MMC_START_CLOCK;
}
/***********************************************************************
*
* Function: mmc_command
*
* Purpose:
* Issues the MMC command to the MM card.
*
* Processing:
* The clock is stopped, while the MMC command, MMC data word, and
* controller command are updated. Then the clock is re-started to
* send the command to the card.
*
* Parameters:
* cmd : Command enumeration
* arg : Command argument
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* This function is private to this module.
*
**********************************************************************/
void mmc_command (UNS_32 cmd, UNS_32 arg)
{
// Stop the clock
mmc_clock_stop ();
// Place the command and argument in the command number and
// argument registers
mmc_regs->command = cmd_data [cmd].cmd;
mmc_regs->argument = arg;
// Update controller command/control word
mmc_regs->cmd_control = cmd_data [cmd].cmdctl;
// Restart clock
mmc_clock_start ();
}
/***********************************************************************
*
* Function: mmc_get_response
*
* Purpose:
* The expected response is read from the MMC response FIFO.
*
* Processing:
* See function.
*
* Parameters:
* buf : Address of where to place response
* bytes : Number of response bytes to copy
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* This function is private to this module.
*
**********************************************************************/
void mmc_get_response (void *buf, INT_32 resp_size)
{
UNS_16 *response;
INT_32 index;
response = (UNS_16 *) buf;
// Wait for response
while ((mmc_regs->status & MMC_STATUS_END_COMMAND_RESPONSE) == 0);
// Read the necessary number of response words from the response
// FIFO
for (index = 0; index < (resp_size / 2); index++)
{
response [index] = mmc_regs->response_fifo;
}
}
/***********************************************************************
*
* Function: mmcif_init
*
* Purpose:
* Initialize the MMC interface.
*
* Processing:
* 1. Determine if an MMC card is inserted. If a card is not inserted,
* retur with a '0' status.
* 2. If inserted, configure the MMC interface to talk to an MMC
* card at a low clock rate (as bus is in open drain mode).
* 3. Issue the MMC_IDLE command (MMC CMD0) to place the card into a
* known reset state.
* 4. Allow a small delay with the MMC clock running to allow the card
* to correctly initialize.
* 5. Attempt to read the OCR word from the card until either the
* number of requests exceeds the request count, or until the OCR
* is valid.
* 6. If the OCR is invalid or there are too many OCR requests, then
* stop the MMC controller clock and exit wih a '0' status.
* 7. If the OCR is valid, send the 'request CID (all)' command.
* 8. Issue the 'set relative card address' command to the card.
* 9. Update the MMC controller clock speed to a much faster speed.
* 10. Read the CSD and CID from the card (just for information).
* 11. Deselect the card (just in case, not needed).
* 12. Stop the MMC controller clock and return with a '1' status.
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* '1' if a MMC card has been initialized, '0' otherwise.
*
* Notes:
* None
*
**********************************************************************/
INT_32 mmcif_init (void)
{
INT_32 i, successful_init, ocr_attempts;
mmc_status_type cstatus;
// 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
successful_init = mmcif_is_card_inserted ();
// Continue if a card is available
if (successful_init == 1)
{
successful_init = 0;
// Disable controller
mmc_regs->clock_prediv = 0;
// Disable SPI mode control functions
mmc_regs->spi = 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->clock_prediv =
(MMC_PREDIV_EN | MMC_PREDIV_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->clock_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);
// This delay allows a minimum of 80 clocks between the CMD0
// request and the initiation of CMD1 and will work with
// code execution speeds as high as 200MHZ (CPU) and bus
// speeds as low as 25MHz. In a OS, this should be replaced
// with a non-blocking timed delay (if possible)
// CYCLES = (80 init clock + 32 command clocks) *
// (200M CPU clocks / 390K MMC clocks) * 4 (bus speed adjusts)
// = 229743 instructions (looped, cached)
for (i = 0; i < 229743; i++);
// Poll card until it has completed the power-up sequence
ocr [0] = 0;
ocr_attempts = MAX_OCR_RET;
while (ocr_attempts > 0)
{
mmc_command (MMC_SOP_COND, VRANGE_OCR);
mmc_get_response (&ocr, sizeof (ocr));
ocr_attempts--;
if ((ocr [0] & OCR_RDY_MASK) != 0)
{
ocr_attempts = 0;
successful_init = 1;
}
}
if (successful_init == 1)
{
// 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->clock_prediv =
(MMC_PREDIV_EN | MMC_PREDIV_APB_RD_EN | MMC_PREDIV(3));
mmc_regs->clock_rate = 1; // (100 / 6) Mbps max
// 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 all cards
mmc_command (MMC_DES_CARD, 0);
mmc_get_response (&cstatus, sizeof (cstatus));
}
// Leave the clock disabled until needed
mmc_clock_stop ();
}
return successful_init;
}
/***********************************************************************
*
* Function: mmcif_shutdown
*
* Purpose:
* Shutdown the MMC interface.
*
* Processing:
* Set the MMC card inactive and disable the MMC clock(s).
*
* 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 without this sequence
mmc_command (MMC_INACTIVE, 0);
mmc_get_response (&cstatus, sizeof (cstatus));
// Disable the MMC clock
mmc_regs->clock_control = MMC_STOP_CLOCK;
// Wait for clock to stop
while ((mmc_regs->status & MMC_STATUS_CLOCK_ENABLED) == 0);
// Disable PCLK to the device
mmc_regs->clock_prediv = mmc_regs->clock_prediv & ~MMC_PREDIV_EN;
}
/***********************************************************************
*
* Function: mmcif_is_card_inserted
*
* Purpose:
* Determine if a card is inserted.
*
* Processing:
* Query the CPLD MMC card insertion bit to determine if an MMC card
* is inserted into the EVB.
*
* 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:
* See function.
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* None
*
**********************************************************************/
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:
* This function is not used and is simply a placeholder for higher
* level drivers.
*
* 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
* places 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:
* Set the (only) MMC card as the active card and set the data block
* size to a single sector size. Pre-empty the data FIFO (safety).
* Issue the 'read single' command to the MMC card with the requested
* sector as the argument.
*
* 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->status & MMC_STATUS_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:
* Set the (only) MMC card as the active card and set the data block
* size to a single sector size. Set the controller write size and
* block count (different from the card block size). Issue the 'write
* single' command to the MMC card with the requested sector as the
* argument.
*
* Parameters:
* None
*
* Outputs:
* None
*
* Returns:
* Nothing
*
* Notes:
* None
*
**********************************************************************/
void mmcif_start_sector_write (void)
{
mmc_status_type cstatus;
// 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));
mmc_regs->block_len = 512;
mmc_regs->nob = 0x01;
// Issue the write block command
mmc_command (MMC_WRITE_SINGLE, next_sector);
mmc_get_response (&cstatus, sizeof (cstatus));
}
/***********************************************************************
*
* Function: mmcif_read_data
*
* Purpose:
* Read a block of data from the MMC card.
*
* Processing:
* This function MUST be called after the 'mmcif_start_sector_read'
* command has been issued. The function will first wait for the data
* transfer to complete. When complete, the data will be read from the
* FIFO into the data buffer. The MMC cards will then be deselected and
* the controller clock will be stopped.
*
* 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:
* Byte swapping of the read data may not be necessary in all systems.
*
**********************************************************************/
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->status & MMC_STATUS_DATA_TRANFER_DONE) == 0);
// Continue reading data until FIFO is empty
while (((mmc_regs->status & MMC_STATUS_FIFO_EMPTY) == 0) &&
(i < (bytes / 2)))
{
// Any data in the FIFO
if ((mmc_regs->status & MMC_STATUS_FIFO_EMPTY) == 0)
{
buf [i] = mmcif_data_swap (mmc_regs->data_fifo);
i++;
}
}
// Set card 'rca' as an inactive card
mmc_command (MMC_DES_CARD, 0);
mmc_get_response (&cstatus, sizeof (cstatus));
// Stop the MMC clock
mmc_clock_stop ();
return bytes;
}
/***********************************************************************
*
* Function: mmcif_write_data
*
* Purpose:
* Write a block of data to the MMC card.
*
* Processing:
* This function MUST be called after the 'mmcif_start_sector_write'
* command has been issued. The function will first wait for the data
* transfer to complete. When complete, the data will be read from the
* FIFO into the data buffer. The MMC cards will then be deselected.
*
* 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;
mmc_status_type cstatus;
UNS_16 *buf = (UNS_16 *) data;
// Write to the FIFO
for (i = 0; i < (bytes / 2); i++)
{
mmc_regs->data_fifo = mmcif_data_swap (buf [i]);
}
// Wait until write operation has ended
while ((mmc_regs->status & MMC_STATUS_PROGRAM_DONE) == 0);
// Set all cards inactive
mmc_command (MMC_DES_CARD, 0);
mmc_get_response (&cstatus, sizeof (cstatus));
return bytes;
}
|