📄 lh7a400_mmc_driver.c
字号:
/***********************************************************************
* $Workfile: LH7A400_mmc_driver.c $
* $Revision: 1.3 $
* $Author: WellsK $
* $Date: Sep 22 2002 14:21:40 $
*
* Project: Multimedia controller interface driver
*
* Description:
* This driver reads and writes raw 'sectors' in the MMC card via
* the Cylinder/Head/Sector (CHS) 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.
*
* Known issues:
* Write operations are not yet supported in this driver. Byte
* swapping code has been temporarily added.
*
* 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.
*
* Revision History:
* $Log: //smaicnt2/pvcs/VM/CHIPS/archives/LH7A400/MMC/Drivers/LH7A400_mmc_driver.c-arc $
*
* 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) 2002 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
* CAMAS, WA
**********************************************************************/
#include "SMA_types.h"
#include "LH7A400_mmc.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
//**********************************************************************
// 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_INITIALIZE | MMC_REPONSE_FORMAT (0))}, // MMC_IDLE
{1, (MMC_REPONSE_FORMAT (3))}, // MMC_SOP
{2, (MMC_REPONSE_FORMAT (2))}, // MMC_ALL_SEND_CID
{3, (MMC_REPONSE_FORMAT (1))}, // MMC_SRA
{7, (MMC_REPONSE_FORMAT (1))}, // MMC_DES_CARD
{9, (MMC_REPONSE_FORMAT (2))}, // MMC_SCSD
{10, (MMC_REPONSE_FORMAT (2))}, // MMC_SCID
{11, (MMC_REPONSE_FORMAT (1))}, // MMC_READ_UNTIL_STOP
{12, (MMC_BUSY | MMC_REPONSE_FORMAT (1))}, // MMC_STOP_TRAN
{13, (MMC_REPONSE_FORMAT (1))}, // MMC_SSTAT
{15, (MMC_REPONSE_FORMAT (1))}, // MMC_INACTIVE
{16, (MMC_REPONSE_FORMAT (1))}, // MMC_SET_BLEN
{17, (MMC_DATA_EN | MMC_REPONSE_FORMAT (1))}, // MMC_READ_SINGLE
{18, (MMC_DATA_EN | MMC_REPONSE_FORMAT (1))}, // MMC_READ_MULTIPLE
{24, (MMC_DATA_EN | MMC_REPONSE_FORMAT (1))}, // MMC_WRITE_SINGLE
{25, (MMC_DATA_EN | MMC_REPONSE_FORMAT (1))} // MMC_WRITE_MULTIPLE
};
/***********************************************************************
*
* Function: mmc_determine_div
*
* Purpose:
* xxx
*
* Processing:
* See function.
*
* Parameters:
* xxx
*
* Outputs:
* None
*
* Returns:
* xxx
*
* Notes:
* This function is private to this module.
*
**********************************************************************/
int mmc_determine_div (UNS_32 nom_freq)
{
UNS_32 lcd_clock, lcd_diff1, lcd_diff2, ahb_speed;
UNS_32 div = 1;
// Get AHB bus speed
ahb_speed = LH7A400_get_hclk ();
lcd_clock = ahb_speed / div;
// Try to get the best divider just under the nominal frequency
while (lcd_clock > nom_freq)
{
div++;
lcd_clock = ahb_speed / div;
}
if (div > 1)
{
// Determine if 'div' or 'div - 1' is closer to nominal frequency
if (lcd_clock > nom_freq)
{
lcd_diff1 = lcd_clock - nom_freq;
}
else
{
lcd_diff1 = nom_freq - lcd_clock;
}
lcd_clock = ahb_speed / (div - 1);
if (lcd_clock > nom_freq)
{
lcd_diff2 = lcd_clock - nom_freq;
}
else
{
lcd_diff2 = nom_freq - lcd_clock;
}
// If diff1 is greater than diff2, then 'div + 1' is the
// closest divider.
if ((lcd_diff1 > lcd_diff2) && (div > 1))
{
div--;
}
}
return div;
}
/***********************************************************************
*
* 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->str_stp_clk = MMC_STOP_CLK;
// Wait for MMC clock to stop
while ((mmc_regs->mmc_status & MMC_CLK_ENABLE) == 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->str_stp_clk = MMC_START_CLK;
// Wait for MMC clock to stop
while ((mmc_regs->mmc_status & MMC_CLK_ENABLE) != 0);
}
/***********************************************************************
*
* Function: mmc_command
*
* Purpose:
* TBD
*
* Processing:
* TBD
*
* 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->cmd_num = cmd_data [cmd].cmd;
mmc_regs->argument = arg;
// Update controller command/control word
mmc_regs->cmd_data_cont = cmd_data [cmd].cmdctl;
// Restart clock
mmc_clock_start ();
}
UNS_16 swap (UNS_32 val)
{
UNS_16 hi, lo;
hi = ((UNS_16) val & 0x00FF) << 8;
lo = ((UNS_16) val & 0xFF00) >> 8;
return (lo + hi);
}
/***********************************************************************
*
* Function: mmc_get_response
*
* Purpose:
* TBD
*
* Processing:
* TBD
*
* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -