/*This file is prepared for Doxygen automatic documentation generation.*/ | |
/*! \file ********************************************************************* | |
* | |
* \brief SD/MMC card driver using MCI interface. | |
* | |
* - Compiler: IAR EWAVR32 and GNU GCC for AVR32 | |
* - Supported devices: All AVR32 devices with an MCI module can be used. | |
* - AppNote: | |
* | |
* \author Atmel Corporation: http://www.atmel.com \n | |
* Support and FAQ: http://support.atmel.no/ | |
* | |
******************************************************************************/ | |
/* Copyright (c) 2009 Atmel Corporation. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright notice, this | |
* list of conditions and the following disclaimer. | |
* | |
* 2. 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. | |
* | |
* 3. The name of Atmel may not be used to endorse or promote products derived | |
* from this software without specific prior written permission. | |
* | |
* 4. This software may only be redistributed and used in connection with an Atmel | |
* AVR product. | |
* | |
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED | |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | |
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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 | |
* | |
*/ | |
//_____ I N C L U D E S ____________________________________________________ | |
#include "conf_access.h" | |
#include <stdio.h> | |
#if SD_MMC_MCI_0_MEM == ENABLE || SD_MMC_MCI_1_MEM == ENABLE | |
#include "gpio.h" | |
#include "mci.h" | |
#include "conf_sd_mmc_mci.h" | |
#include "sd_mmc_mci.h" | |
#include "cycle_counter.h" | |
//_____ P R I V A T E D E C L A R A T I O N S ____________________________ | |
// Variable to manage the specification of the card | |
Bool sd_mmc_mci_init_done[MCI_NR_SLOTS] = {FALSE, FALSE}; | |
U8 g_u8_card_type[ MCI_NR_SLOTS]; // Global Card Type | |
U32 g_u32_card_rca[ MCI_NR_SLOTS]; // Global RCA | |
U32 g_u32_card_size[ MCI_NR_SLOTS]; // Global Card Size | |
U16 g_u16_card_freq[ MCI_NR_SLOTS]; // Global Card Frequency | |
U8 g_u8_card_bus_width[ MCI_NR_SLOTS]; // Global Card Bus Width | |
// These buffers should be dynamically allocated; may be in the sd_mmc driver initialization. | |
COMPILER_WORD_ALIGNED | |
uint8_t sector_buf_0[SD_MMC_SECTOR_SIZE]; | |
COMPILER_WORD_ALIGNED | |
uint8_t sector_buf_1[SD_MMC_SECTOR_SIZE]; | |
// Global Pbb Speed in case of reinitialization Launch | |
U32 g_pbb_hz = 0; | |
// Global Cpu speed, needed by the cpu_delay() function | |
U32 g_cpu_hz = 0; | |
// Variables to manage a standby/restart access | |
volatile U32 gl_ptr_mem[MCI_NR_SLOTS]={0, 0}; | |
// MCI Instance | |
volatile avr32_mci_t *mci = &AVR32_MCI; | |
static Bool sd_mmc_mci_get_csd(U8 slot); | |
static Bool sd_mmc_get_ext_csd( U8 slot ); | |
static Bool sd_mmc_set_block_len(U8 slot, U16 length ); | |
#if ACCESS_USB == ENABLED | |
static Bool is_dma_ram_2_mci_complete( void ); | |
static void dma_ram_2_mci(const void *ram, size_t size); | |
static Bool is_dma_mci_2_ram_complete( void ); | |
static void dma_mci_2_ram(void *ram, size_t size); | |
#include "conf_usb.h" | |
#ifndef USB_DEVICE_VENDOR_ID | |
// USB Device Stack V1 | |
static Bool is_dma_usb_2_ram_complete( void ); | |
static void dma_usb_2_ram(void *ram, size_t size); | |
static Bool is_dma_ram_2_usb_complete( void ); | |
static void dma_ram_2_usb(const void *ram, size_t size); | |
#endif | |
#endif | |
//_____ D E F I N I T I O N S ______________________________________________ | |
Bool is_sd_mmc_mci_card_present(U8 slot) | |
{ | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
switch(slot) | |
{ | |
case MCI_SLOT_B: | |
return (gpio_get_pin_value(SD_SLOT_4BITS_CARD_DETECT)==SD_SLOT_4BITS_CARD_DETECT_VALUE); | |
case MCI_SLOT_A: | |
return (gpio_get_pin_value(SD_SLOT_8BITS_CARD_DETECT)==SD_SLOT_8BITS_CARD_DETECT_VALUE); | |
} | |
return FALSE; | |
} | |
Bool is_sd_mmc_mci_card_protected(U8 slot) | |
{ | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
switch(slot) | |
{ | |
case MCI_SLOT_B: | |
return (gpio_get_pin_value(SD_SLOT_4BITS_WRITE_PROTECT)==SD_SLOT_4BITS_WRITE_PROTECT_VALUE); | |
case MCI_SLOT_A: | |
return (gpio_get_pin_value(SD_SLOT_8BITS_WRITE_PROTECT)==SD_SLOT_8BITS_WRITE_PROTECT_VALUE); | |
} | |
return FALSE; | |
} | |
static Bool sd_mmc_mci_get_csd(U8 slot) | |
{ | |
csd_t csd; | |
U32 max_Read_DataBlock_Length; | |
U32 mult; | |
U32 blocknr; | |
U8 tmp; | |
const U16 freq_unit[4] = {10, 100, 1000, 10000}; | |
const U8 mult_fact[16] = {0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80}; // MMC tabs... | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
//-- (CMD9) | |
if (mci_send_cmd(mci, SD_MMC_SEND_CSD_CMD, g_u32_card_rca[slot])!=MCI_SUCCESS) | |
return FALSE; | |
csd.csd[0] = mci_read_response(mci); | |
csd.csd[1] = mci_read_response(mci); | |
csd.csd[2] = mci_read_response(mci); | |
csd.csd[3] = mci_read_response(mci); | |
//-- Read "System specification version", only available on MMC card | |
// field: SPEC_VERS (only on MMC) | |
if (MMC_CARD & g_u8_card_type[slot]) // TO BE ADDED | |
{ | |
if (CSD_SPEC_VER_4_0 == (MSB0(csd.csd[0]) & CSD_MSK_SPEC_VER)) | |
{ | |
g_u8_card_type[slot] |= MMC_CARD_V4; | |
} | |
} | |
//-- Compute MMC/SD speed | |
// field: TRAN_SPEED (CSD V1 & V2 are the same) | |
g_u16_card_freq[slot] = mult_fact[csd.csd_v1.tranSpeed >> 3]; // Get Multiplier factor | |
if (SD_CARD & g_u8_card_type[slot]) | |
{ | |
// SD card don't have same frequency that MMC card | |
if( 26 == g_u16_card_freq[slot] ) | |
{ | |
g_u16_card_freq[slot] = 25; | |
} | |
else if( 52 == g_u16_card_freq[slot] ) | |
{ | |
g_u16_card_freq[slot] = 50; | |
} | |
} | |
g_u16_card_freq[slot] *= freq_unit[ csd.csd_v1.tranSpeed&0x07 ]; // Get transfer rate unit | |
//-- Compute card size in number of block | |
// field: WRITE_BL_LEN, READ_BL_LEN, C_SIZE (CSD V1 & V2 are not the same) | |
if (SD_CARD_HC & g_u8_card_type[slot]) | |
{ | |
g_u32_card_size[slot] = (csd.csd_v2.deviceSizeH<<16)+(csd.csd_v2.deviceSizeL&0xFFff); | |
// memory capacity = (C_SIZE+1) * 1K sector | |
g_u32_card_size[slot] = (g_u32_card_size[slot] + 1) << 10; // unit 512B | |
} | |
else | |
{ | |
// Check block size | |
tmp = csd.csd_v1.writeBlLen; // WRITE_BL_LEN | |
if (tmp < CSD_BLEN_512) | |
return FALSE; // block size < 512B not supported by firmware | |
tmp = csd.csd_v1.readBlLen; // READ_BL_LEN | |
if (tmp < CSD_BLEN_512) | |
return FALSE; // block size < 512B not supported by firmware | |
//// Compute Memory Capacity | |
// compute MULT | |
mult = 1 << (csd.csd_v1.cSizeMult + 2); | |
max_Read_DataBlock_Length = 1<<csd.csd_v1.readBlLen; | |
// compute MSB of C_SIZE | |
blocknr = csd.csd_v1.deviceSizeH << 2; | |
// compute MULT * (LSB of C-SIZE + MSB already computed + 1) = BLOCKNR | |
blocknr = mult * ( blocknr + csd.csd_v1.deviceSizeL + 1 ); | |
g_u32_card_size[slot] = ((max_Read_DataBlock_Length * blocknr)/512); | |
} | |
return TRUE; | |
} | |
static Bool sd_mmc_get_ext_csd( U8 slot ) | |
{ | |
U8 i; | |
U32 val; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
mci_set_block_size(mci, SD_MMC_SECTOR_SIZE); // Ext CSD = 512B size | |
mci_set_block_count(mci, 1); | |
//** (CMD8) | |
// read the extended CSD | |
if(mci_send_cmd(mci, SD_MMC_SEND_EXT_CSD_CMD, 0 )!=MCI_SUCCESS) | |
return FALSE; | |
// READ_EXT_CSD // discard bytes not used | |
for (i = (512L/8); i!=0; i--) | |
{ | |
while(!(mci_rx_ready(mci))); | |
mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
if( ((64-26) == i) && (g_u8_card_type[slot]&MMC_CARD_HC) ) | |
{ | |
// If MMC HC then read Sector Count. Byte 212 is LSB, Byte 215 is MSB. | |
val = mci_rd_data(mci); | |
g_u32_card_size[slot] = swap32(val); | |
} | |
else | |
{ | |
val = mci_rd_data(mci); | |
if( (64-24) == i ) | |
{ // Read byte at offset 196 | |
if( MSB0(val) & 0x02 ) | |
g_u16_card_freq[slot] = 52*1000; | |
else | |
g_u16_card_freq[slot] = 26*1000; | |
} | |
} | |
} | |
return TRUE; | |
} | |
static Bool sd_mmc_set_block_len(U8 slot, U16 length ) | |
{ | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
if(mci_send_cmd(mci, SD_MMC_SET_BLOCKLEN_CMD, length)!=MCI_SUCCESS) | |
return FALSE; | |
// check response, card must be in TRAN state | |
if ((mci_read_response(mci) & MMC_TRAN_STATE_MSK) != MMC_TRAN_STATE) | |
return FALSE; | |
mci_set_block_size(mci, length); | |
mci_set_block_count(mci, 1); | |
return TRUE; | |
} | |
Bool sd_mmc_mci_init(unsigned char card_slot, long pbb_hz, long cpu_hz) | |
{ | |
union | |
{ | |
unsigned long mcfg; | |
avr32_hmatrix_mcfg_t MCFG; | |
} u_avr32_hmatrix_mcfg; | |
union | |
{ | |
unsigned long scfg; | |
avr32_hmatrix_scfg_t SCFG; | |
} u_avr32_hmatrix_scfg; | |
// For the USBB DMA HMATRIX master, use infinite length burst. | |
u_avr32_hmatrix_mcfg.mcfg = AVR32_HMATRIX.mcfg[AVR32_HMATRIX_MASTER_USBB_DMA]; | |
u_avr32_hmatrix_mcfg.MCFG.ulbt = AVR32_HMATRIX_ULBT_INFINITE; | |
AVR32_HMATRIX.mcfg[AVR32_HMATRIX_MASTER_USBB_DMA] = u_avr32_hmatrix_mcfg.mcfg; | |
// For the USBB DPRAM HMATRIX slave, use the USBB DMA as fixed default master. | |
u_avr32_hmatrix_scfg.scfg = AVR32_HMATRIX.scfg[AVR32_HMATRIX_SLAVE_USBB_DPRAM]; | |
u_avr32_hmatrix_scfg.SCFG.fixed_defmstr = AVR32_HMATRIX_MASTER_USBB_DMA; | |
u_avr32_hmatrix_scfg.SCFG.defmstr_type = AVR32_HMATRIX_DEFMSTR_TYPE_FIXED_DEFAULT; | |
AVR32_HMATRIX.scfg[AVR32_HMATRIX_SLAVE_USBB_DPRAM] = u_avr32_hmatrix_scfg.scfg; | |
g_pbb_hz = pbb_hz; | |
g_cpu_hz = cpu_hz; | |
// Init MCI controler | |
if (mci_init(mci, card_slot, pbb_hz)!=MCI_SUCCESS) | |
return FALSE; | |
// Default card initialization. This can be removed since the card init will | |
// automatically be done when needed. | |
sd_mmc_mci_card_init(card_slot); | |
return TRUE; | |
} | |
Bool sd_mmc_mci_card_init(unsigned char slot) | |
{ | |
U32 u32_response; | |
if (TRUE == sd_mmc_mci_init_done[slot]) | |
return TRUE; | |
// Default card is not known. | |
g_u8_card_type[slot] = UNKNOWN_CARD; | |
// Default bus size is 1 bit. | |
g_u8_card_bus_width[slot] = MCI_BUS_SIZE_1_BIT; | |
// Default card speed and disable High Speed mode. | |
mci_init(mci, slot, g_pbb_hz); | |
// Wait for 1ms, then wait for 74 more clock cycles (see MMC norms) | |
if (mci_send_cmd(mci, SD_MMC_INIT_STATE_CMD, 0xFFFFFFFF)!=MCI_SUCCESS) | |
return FALSE; | |
//-- (CMD0) | |
// Set card in idle state | |
if (mci_send_cmd(mci, SD_MMC_GO_IDLE_STATE_CMD, 0xFFFFFFFF)!=MCI_SUCCESS) | |
return FALSE; | |
sd_mmc_init_step1: | |
// (CMD1) | |
// To send its Operating Conditions Register contents command only supported by MMC card | |
if(mci_send_cmd(mci, SD_MMC_MMC_SEND_OP_COND_CMD, OCR_MSK_BUSY|OCR_MSK_VOLTAGE_ALL|OCR_MSK_HC)==MCI_SUCCESS) | |
{ | |
// MMC cards always respond to MMC_SEND_OP_COND | |
g_u8_card_type[slot] = MMC_CARD; | |
u32_response = mci_read_response(mci); | |
if( !(u32_response & OCR_MSK_BUSY) ) | |
{ | |
// here card busy, it did not completed its initialization process | |
// resend command MMC_SEND_OP_COND | |
goto sd_mmc_init_step1; // loop until it is ready | |
} | |
if( 0!=(u32_response & OCR_MSK_HC) ) | |
{ | |
g_u8_card_type[slot] |= MMC_CARD_HC; | |
} | |
} | |
else | |
{ | |
// SD cards do not respond to MMC_SEND_OP_COND | |
g_u8_card_type[slot] = SD_CARD; | |
//-- (CMD8) | |
// enables to expand new functionality to some existing commands supported only by SD HC card | |
if (mci_send_cmd(mci, SD_MMC_SD_SEND_IF_COND_CMD, 0x000001AA)==MCI_SUCCESS) | |
{ | |
// It is a SD HC | |
if( 0x000001AA == mci_read_response(mci)) | |
{ | |
g_u8_card_type[slot] |= SD_CARD_V2; | |
} | |
} | |
sd_mmc_init_step2: | |
//-- (CMD55) | |
// Indicates to the card that the next command is an application specific command rather than a standard command | |
// CMD55 shall always precede ACMD41 | |
if (mci_send_cmd(mci, SD_MMC_APP_CMD, 0)!=MCI_SUCCESS) | |
return FALSE; | |
//-- (ACMD41) | |
// Sends host OCR register | |
if( SD_CARD_V2 & g_u8_card_type[slot] ) | |
{ | |
// Sends host capacity support information (HCS) | |
if (mci_send_cmd(mci, SD_MMC_SDCARD_APP_OP_COND_CMD, OCR_MSK_BUSY|OCR_MSK_VOLTAGE_3_2V_3_3V|OCR_MSK_HC)!=MCI_SUCCESS) | |
return FALSE; | |
} | |
else | |
{ | |
if (mci_send_cmd(mci, SD_MMC_SDCARD_APP_OP_COND_CMD, OCR_MSK_BUSY|OCR_MSK_VOLTAGE_3_2V_3_3V)!=MCI_SUCCESS) | |
return FALSE; | |
} | |
u32_response = mci_read_response(mci); | |
if( !(u32_response & OCR_MSK_BUSY) ) | |
{ | |
// Card Busy, resend ACMD41 precede of CMD55 | |
goto sd_mmc_init_step2; | |
} | |
// Card read then check HC type | |
if (u32_response & OCR_MSK_HC) | |
{ | |
g_u8_card_type[slot] |= SD_CARD_HC; // Card SD High Capacity | |
} | |
} | |
// Here card ready and type (MMC <V4, MMC V4, MMC HC, SD V1, SD V2 HC) detected | |
//-- (CMD2) | |
// Send CID | |
if (mci_send_cmd(mci, SD_MMC_ALL_SEND_CID_CMD, 0)!=MCI_SUCCESS) | |
return FALSE; | |
//-- (CMD3) | |
// Set relative address | |
if(MMC_CARD & g_u8_card_type[slot]) | |
{ | |
// For MMC card, you send an address to card | |
g_u32_card_rca[slot] = RCA_DEFAULT_ADR; | |
if(mci_send_cmd(mci, SD_MMC_SET_RELATIVE_ADDR_CMD, RCA_DEFAULT_ADR)!=MCI_SUCCESS) | |
return FALSE; | |
} | |
else | |
{ | |
// For SD card, you ask an address to card | |
if(mci_send_cmd(mci, SD_MMC_SET_RELATIVE_ADDR_CMD, RCA_RESERVE_ADR)!=MCI_SUCCESS) | |
return FALSE; | |
} | |
if (SD_CARD & g_u8_card_type[slot]) | |
{ | |
// For SD card, you receiv address of card | |
g_u32_card_rca[slot] = mci_read_response(mci) & RCA_MSK_ADR ; | |
} | |
//-- (CMD9) | |
// Read & analyse CSD register | |
if (sd_mmc_mci_get_csd(slot)!=TRUE) | |
return FALSE; | |
//-- (CMD7)-R1b | |
// select card | |
if (mci_send_cmd(mci, SD_MMC_SEL_DESEL_CARD_CMD, g_u32_card_rca[slot])!=MCI_SUCCESS) | |
return FALSE; | |
// Wait end of busy | |
mci_wait_busy_signal(mci);// read busy state on DAT0 | |
// Get clock by checking the extended CSD register | |
if (MMC_CARD_V4 & g_u8_card_type[slot]) | |
{ | |
// Get clock (MMC V4) and size (MMC V4 HC) by checking the extended CSD register | |
//-- (CMD8) | |
if (sd_mmc_get_ext_csd(slot)!=TRUE) | |
return FALSE; | |
} | |
#if (SD_4_BIT == ENABLE) | |
// set bus size | |
if (SD_CARD & g_u8_card_type[slot]) | |
{ | |
// set 4-bit bus for SD Card | |
//-- (CMD55) | |
if(mci_send_cmd(mci, SD_MMC_APP_CMD, g_u32_card_rca[slot])!=MCI_SUCCESS) | |
return FALSE; | |
//-- (CMD6) | |
if(mci_send_cmd(mci, SD_MMC_SDCARD_SET_BUS_WIDTH_CMD, SD_BUS_4_BIT )!=MCI_SUCCESS) | |
return FALSE; | |
g_u8_card_bus_width[slot] = MCI_BUS_SIZE_4_BIT; | |
if (mci_set_bus_size(mci, g_u8_card_bus_width[slot])!=MCI_SUCCESS) | |
return FALSE; | |
} | |
else // MMC bus width management | |
{ | |
// set 8-bit bus for MMC Card | |
if (MMC_CARD_V4 & g_u8_card_type[slot]) | |
{ | |
//-- (CMD6)-R1b | |
// set 8-bit bus width (appeared from V4.0 specification) | |
if (mci_send_cmd( mci, | |
MMC_SWITCH_CMD, | |
( (U32)MMC_SWITCH_WRITE <<24)| | |
((U32)MMC_SWITCH_BUS_WIDTH<<16)| | |
((U32)MMC_SWITCH_VAL_8BIT << 8)| | |
((U32)MMC_SWITCH_CMD_SET))!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// Wait end of busy | |
mci_wait_busy_signal(mci);// read busy state on DAT0 | |
g_u8_card_bus_width[slot] = MCI_BUS_SIZE_8_BIT; | |
if (mci_set_bus_size(mci, g_u8_card_bus_width[slot])!=MCI_SUCCESS) | |
return FALSE; | |
} | |
} | |
#endif | |
if (MMC_CARD_V4 & g_u8_card_type[slot]) | |
{ | |
//-- (CMD6)-R1b | |
// set high speed interface timing | |
if (mci_send_cmd( mci, | |
MMC_SWITCH_CMD, | |
((U32)MMC_SWITCH_WRITE <<24)| | |
((U32)MMC_SWITCH_HIGH_SPEED<<16)| | |
((U32)MMC_SWITCH_VAL_HS << 8)| | |
((U32)MMC_SWITCH_CMD_SET))!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// Wait end of busy | |
mci_wait_busy_signal(mci); | |
} | |
if( SD_CARD_V2 & g_u8_card_type[slot] ) | |
{ | |
/** \brief Switch func argument definitions */ | |
#define SDMMC_SWITCH_FUNC_MODE_CHECK (0 << 31) /**< Check function */ | |
#define SDMMC_SWITCH_FUNC_MODE_SWITCH (1 << 31) /**< Switch function */ | |
#define SDMMC_SWITCH_FUNC_HIGH_SPEED (1 << 0) /**< High Speed */ | |
#define SDMMC_SWITCH_FUNC_G1_KEEP (0xf << 0) /**< Group 1 No influence */ | |
#define SDMMC_SWITCH_FUNC_G2_KEEP (0xf << 4) /**< Group 2 No influence */ | |
#define SDMMC_SWITCH_FUNC_G3_KEEP (0xf << 8) /**< Group 3 No influence */ | |
#define SDMMC_SWITCH_FUNC_G4_KEEP (0xf << 12) /**< Group 4 No influence */ | |
#define SDMMC_SWITCH_FUNC_G5_KEEP (0xf << 16) /**< Group 5 No influence */ | |
#define SDMMC_SWITCH_FUNC_G6_KEEP (0xf << 20) /**< Group 6 No influence */ | |
mci_set_block_size(mci, 512/8); // CMD6 512 bits status | |
mci_set_block_count(mci, 1); | |
//-- (CMD6) | |
// Check if we can enter into the High Speed mode. | |
if (mci_send_cmd( mci | |
, SD_SWITCH_FUNC | |
, SDMMC_SWITCH_FUNC_MODE_CHECK | SDMMC_SWITCH_FUNC_HIGH_SPEED | |
)!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// Wait end of busy | |
mci_wait_busy_signal(mci);// read busy state on DAT0 | |
Bool b_hs_supported=FALSE; | |
{ | |
U8 i; | |
for ( i = 0; i<(512L/8); i+=4) | |
{ | |
volatile U32 data; | |
while(!(mci_rx_ready(mci))); | |
data = mci_rd_data(mci); | |
if(i==16) | |
{ | |
if(((data>>24)&0xf)==1) | |
b_hs_supported=TRUE; | |
break; | |
} | |
} | |
} | |
if (b_hs_supported==FALSE ) | |
goto sd_mmc_init_step3; | |
if (mci_send_cmd( mci | |
, SD_SWITCH_FUNC | |
, SDMMC_SWITCH_FUNC_MODE_SWITCH | |
| SDMMC_SWITCH_FUNC_G6_KEEP | |
| SDMMC_SWITCH_FUNC_G5_KEEP | |
| SDMMC_SWITCH_FUNC_G4_KEEP | |
| SDMMC_SWITCH_FUNC_G3_KEEP | |
| SDMMC_SWITCH_FUNC_G2_KEEP | |
| SDMMC_SWITCH_FUNC_HIGH_SPEED | |
)!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
{ | |
U8 i; | |
for ( i = 0; i<(512L/8); i+=4) | |
{ | |
volatile U32 data; | |
while(!(mci_rx_ready(mci))); | |
data = mci_rd_data(mci); | |
} | |
} | |
/* A 8 cycle delay is required after switch command | |
* @ 200KHz clock this should be 40 uS, but we use | |
* 80 to handle unprecise clock setting. | |
*/ | |
cpu_delay_us(80, g_cpu_hz); | |
union u_cfg{ | |
unsigned long cfg; | |
avr32_mci_cfg_t CFG; | |
}; | |
union u_cfg val; | |
val.cfg = mci->cfg; | |
val.CFG.hsmode = 1; | |
mci->cfg = val.cfg; | |
// deselect card | |
if (mci_send_cmd(mci, SD_MMC_SEL_DESEL_CARD_CMD, 0)!=MCI_SUCCESS) | |
return FALSE; | |
// Wait end of busy | |
mci_wait_busy_signal(mci);// read busy state on DAT0 | |
//-- (CMD9) | |
// Read & analyse CSD register | |
if (sd_mmc_mci_get_csd(slot)!=TRUE) | |
return FALSE; | |
// select card | |
if (mci_send_cmd(mci, SD_MMC_SEL_DESEL_CARD_CMD, g_u32_card_rca[slot])!=MCI_SUCCESS) | |
return FALSE; | |
// Wait end of busy | |
mci_wait_busy_signal(mci);// read busy state on DAT0 | |
} | |
sd_mmc_init_step3: | |
// Set clock | |
mci_set_speed(mci, g_pbb_hz, g_u16_card_freq[slot]*1000); | |
//-- (CMD13) | |
// Check if card is ready, the card must be in TRAN state | |
if(sd_mmc_mci_cmd_send_status(slot)!=TRUE) | |
return FALSE; | |
if ((mci_read_response(mci) & MMC_TRAN_STATE_MSK) != MMC_TRAN_STATE) | |
return FALSE; | |
//-- (CMD16) | |
// Set the card block length to 512B | |
if (sd_mmc_set_block_len (slot, SD_MMC_SECTOR_SIZE)!=TRUE) | |
return FALSE; | |
// USB Test Unit Attention requires a state "busy" between "not present" and "ready" state | |
// otherwise never report card change | |
sd_mmc_mci_init_done[slot] = TRUE; | |
return TRUE; | |
} | |
Bool sd_mmc_mci_read_sector_2_ram(U8 slot, void *ram) | |
{ | |
U32 wordsToRead; | |
int *pRam = ram; | |
// Read data | |
wordsToRead = (SD_MMC_SECTOR_SIZE/sizeof(*pRam)); | |
while(wordsToRead>0) | |
{ | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
wordsToRead-=8; | |
} | |
return TRUE; | |
} | |
Bool sd_mmc_mci_dma_read_sector_2_ram(U8 slot, void *ram) | |
{ | |
int *pRam = ram; | |
// Src Address: the MCI registers. | |
AVR32_DMACA.sar1 = (U32)&AVR32_MCI.fifo; | |
// Dst Address: the OutputData[] array. | |
AVR32_DMACA.dar1 = (unsigned long)pRam; | |
// Channel 1 Ctrl register high | |
AVR32_DMACA.ctl1h = | |
( (SD_MMC_SECTOR_SIZE/4) << AVR32_DMACA_CTL1H_BLOCK_TS_OFFSET) // Block transfer size | |
; | |
// Enable Channel 1 : start the process. | |
AVR32_DMACA.chenreg = ((2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET) | (2<<AVR32_DMACA_CHENREG_CH_EN_WE_OFFSET)); | |
// Wait for the end of the AES->RAM transfer (channel 1). | |
while(AVR32_DMACA.chenreg & (2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET)); | |
return TRUE; | |
} | |
Bool sd_mmc_mci_read_multiple_sector_2_ram(U8 slot, void *ram, U32 nb_sector) | |
{ | |
U32 wordsToRead; | |
int *pRam = ram; | |
// Read data | |
while( nb_sector>0 ) | |
{ | |
wordsToRead = (SD_MMC_SECTOR_SIZE/sizeof(*pRam)); | |
while(wordsToRead>0) | |
{ | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
while(!(mci_rx_ready(mci))); | |
*pRam++ = mci_rd_data(mci); | |
wordsToRead-=8; | |
} | |
nb_sector--; | |
} | |
return TRUE; | |
} | |
#if ACCESS_USB == ENABLED | |
#ifndef USB_DEVICE_VENDOR_ID | |
// USB Device Stack V1 | |
#include "usb_drv.h" | |
#include "scsi_decoder.h" | |
static void dma_ram_2_usb(const void *ram, size_t size) | |
{ | |
AVR32_USBB_UDDMAX_nextdesc(g_scsi_ep_ms_in) = (U32)NULL; | |
AVR32_USBB_UDDMAX_addr(g_scsi_ep_ms_in) = (U32)ram; | |
AVR32_USBB_UDDMAX_control(g_scsi_ep_ms_in) = ((size << AVR32_USBB_UXDMAX_CONTROL_CH_BYTE_LENGTH_OFFSET) | |
& AVR32_USBB_UXDMAX_CONTROL_CH_BYTE_LENGTH_MASK) | |
//| AVR32_USBB_UXDMAX_CONTROL_BURST_LOCK_EN_MASK | |
//| AVR32_USBB_UXDMAX_CONTROL_DMAEND_EN_MASK | |
//| AVR32_USBB_UXDMAX_CONTROL_BUFF_CLOSE_IN_EN_MASK | |
| AVR32_USBB_UXDMAX_CONTROL_CH_EN_MASK; | |
// Workaround for bug 3501. | |
(void)AVR32_USBB_UDDMAX_control(g_scsi_ep_ms_in); | |
} | |
static Bool is_dma_ram_2_usb_complete( void ) | |
{ | |
if(AVR32_USBB_UDDMAX_status(g_scsi_ep_ms_in) & AVR32_USBB_UXDMAX_STATUS_CH_EN_MASK) | |
return FALSE; | |
else | |
return TRUE; | |
} | |
#endif | |
static void dma_mci_2_ram(void *ram, size_t size) | |
{ | |
int *pRam = ram; | |
// Src Address: the MCI registers. | |
AVR32_DMACA.sar1 = (U32)&AVR32_MCI.fifo; | |
// Dst Address: the OutputData[] array. | |
AVR32_DMACA.dar1 = (unsigned long)pRam; | |
// Channel 1 Ctrl register high | |
AVR32_DMACA.ctl1h = | |
( (size/4) << AVR32_DMACA_CTL1H_BLOCK_TS_OFFSET) // Block transfer size | |
; | |
// Enable Channel 1 : start the process. | |
AVR32_DMACA.chenreg = ((2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET) | (2<<AVR32_DMACA_CHENREG_CH_EN_WE_OFFSET)); | |
} | |
static Bool is_dma_mci_2_ram_complete( void ) | |
{ | |
// Wait for the end of the AES->RAM transfer (channel 1). | |
if (AVR32_DMACA.chenreg & (2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET)) | |
return FALSE; | |
return TRUE; | |
} | |
#endif | |
Bool sd_mmc_mci_dma_read_multiple_sector_2_ram(U8 slot, void *ram, U32 nb_sector) | |
{ | |
int *pRam = ram; | |
// Src Address: the MCI registers. | |
AVR32_DMACA.sar1 = (U32)&AVR32_MCI.fifo; | |
// Dst Address: the OutputData[] array. | |
AVR32_DMACA.dar1 = (unsigned long)pRam; | |
// Channel 1 Ctrl register high | |
AVR32_DMACA.ctl1h = | |
( (nb_sector*(SD_MMC_SECTOR_SIZE/4)) << AVR32_DMACA_CTL1H_BLOCK_TS_OFFSET) // Block transfer size | |
; | |
// Enable Channel 1 : start the process. | |
AVR32_DMACA.chenreg = ((2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET) | (2<<AVR32_DMACA_CHENREG_CH_EN_WE_OFFSET)); | |
// Wait for the end of the AES->RAM transfer (channel 1). | |
while(AVR32_DMACA.chenreg & (2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET)); | |
return TRUE; | |
} | |
Bool sd_mmc_mci_write_sector_from_ram(U8 slot, const void *ram) | |
{ | |
U32 wordsToWrite; | |
const unsigned int *pRam = ram; | |
// Write Data | |
wordsToWrite = (SD_MMC_SECTOR_SIZE/sizeof(*pRam)); | |
while(wordsToWrite>0) | |
{ | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
wordsToWrite-=8; | |
} | |
return TRUE; | |
} | |
Bool sd_mmc_mci_dma_write_sector_from_ram(U8 slot, const void *ram) | |
{ | |
const unsigned int *pRam = ram; | |
// Dst Address: the OutputData[] array. | |
AVR32_DMACA.sar1 = (unsigned long)pRam; | |
// Src Address: the MCI registers. | |
AVR32_DMACA.dar1 = (U32)&AVR32_MCI.fifo; | |
// Channel 1 Ctrl register high | |
AVR32_DMACA.ctl1h = | |
( (SD_MMC_SECTOR_SIZE/4) << AVR32_DMACA_CTL1H_BLOCK_TS_OFFSET) // Block transfer size | |
; | |
// Enable Channel 1 : start the process. | |
AVR32_DMACA.chenreg = ((2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET) | (2<<AVR32_DMACA_CHENREG_CH_EN_WE_OFFSET)); | |
// Wait for the end of the AES->RAM transfer (channel 1). | |
while(AVR32_DMACA.chenreg & (2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET)); | |
return TRUE; | |
} | |
Bool sd_mmc_mci_write_multiple_sector_from_ram(U8 slot, const void *ram, U32 nb_sector) | |
{ | |
U32 wordsToWrite; | |
const unsigned int *pRam = ram; | |
// Write Data | |
while( nb_sector>0 ) | |
{ | |
wordsToWrite = (SD_MMC_SECTOR_SIZE/sizeof(*pRam)); | |
while(wordsToWrite>0) | |
{ | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
while(!mci_tx_ready(mci)); | |
mci_wr_data(mci,*pRam++); | |
wordsToWrite-=8; | |
} | |
nb_sector--; | |
} | |
return TRUE; | |
} | |
#if ACCESS_USB == ENABLED | |
#ifndef USB_DEVICE_VENDOR_ID | |
// USB Device Stack V1 | |
#include "usb_drv.h" | |
#include "scsi_decoder.h" | |
static void dma_usb_2_ram(void *ram, size_t size) | |
{ | |
AVR32_USBB_UDDMAX_nextdesc(g_scsi_ep_ms_out) = (U32)NULL; | |
AVR32_USBB_UDDMAX_addr(g_scsi_ep_ms_out) = (U32)ram; | |
AVR32_USBB_UDDMAX_control(g_scsi_ep_ms_out) = ((size << AVR32_USBB_UXDMAX_CONTROL_CH_BYTE_LENGTH_OFFSET) | |
& AVR32_USBB_UXDMAX_CONTROL_CH_BYTE_LENGTH_MASK) | |
//| AVR32_USBB_UXDMAX_CONTROL_BURST_LOCK_EN_MASK | |
//| AVR32_USBB_UXDMAX_CONTROL_DMAEND_EN_MASK | |
//| AVR32_USBB_UXDMAX_CONTROL_BUFF_CLOSE_IN_EN_MASK | |
| AVR32_USBB_UXDMAX_CONTROL_CH_EN_MASK; | |
// Workaround for bug 3501. | |
(void)AVR32_USBB_UDDMAX_control(g_scsi_ep_ms_out); | |
} | |
static Bool is_dma_usb_2_ram_complete( void ) | |
{ | |
if(AVR32_USBB_UDDMAX_status(g_scsi_ep_ms_out) & AVR32_USBB_UXDMAX_STATUS_CH_EN_MASK) | |
return FALSE; | |
else | |
return TRUE; | |
} | |
#endif | |
static void dma_ram_2_mci(const void *ram, size_t size) | |
{ | |
const unsigned int *pRam = ram; | |
// Dst Address: the OutputData[] array. | |
AVR32_DMACA.sar1 = (unsigned long)pRam; | |
// Src Address: the MCI registers. | |
AVR32_DMACA.dar1 = (U32)&AVR32_MCI.fifo; | |
// Channel 1 Ctrl register high | |
AVR32_DMACA.ctl1h = | |
( (size/4) << AVR32_DMACA_CTL1H_BLOCK_TS_OFFSET) // Block transfer size | |
; | |
// Enable Channel 1 : start the process. | |
AVR32_DMACA.chenreg = ((2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET) | (2<<AVR32_DMACA_CHENREG_CH_EN_WE_OFFSET)); | |
} | |
static Bool is_dma_ram_2_mci_complete( void ) | |
{ | |
// Wait for the end of the AES->RAM transfer (channel 1). | |
if (AVR32_DMACA.chenreg & (2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET)) | |
return FALSE; | |
return TRUE; | |
} | |
#endif | |
Bool sd_mmc_mci_dma_write_multiple_sector_from_ram(U8 slot, const void *ram, U32 nb_sector) | |
{ | |
const unsigned int *pRam = ram; | |
// Dst Address: the OutputData[] array. | |
AVR32_DMACA.sar1 = (unsigned long)pRam; | |
// Src Address: the MCI registers. | |
AVR32_DMACA.dar1 = (U32)&AVR32_MCI.fifo; | |
// Channel 1 Ctrl register high | |
AVR32_DMACA.ctl1h = | |
( (nb_sector*(SD_MMC_SECTOR_SIZE/4)) << AVR32_DMACA_CTL1H_BLOCK_TS_OFFSET) // Block transfer size | |
; | |
// Enable Channel 1 : start the process. | |
AVR32_DMACA.chenreg = ((2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET) | (2<<AVR32_DMACA_CHENREG_CH_EN_WE_OFFSET)); | |
// Wait for the end of the AES->RAM transfer (channel 1). | |
while(AVR32_DMACA.chenreg & (2<<AVR32_DMACA_CHENREG_CH_EN_OFFSET)); | |
return TRUE; | |
} | |
Bool sd_mmc_mci_mem_check(U8 slot) | |
{ | |
U8 timeout_init = 0; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
// Check card presence | |
if (is_sd_mmc_mci_card_present(slot) == FALSE) | |
{ | |
sd_mmc_mci_init_done[slot] = FALSE; | |
return FALSE; | |
} | |
if (sd_mmc_mci_init_done[slot] == FALSE) | |
{ | |
while (sd_mmc_mci_card_init(slot)!=TRUE) | |
{ | |
timeout_init++; | |
if (timeout_init>10) return FALSE; | |
} | |
} | |
if (sd_mmc_mci_init_done[slot] == TRUE) | |
return TRUE; | |
else | |
return FALSE; | |
} | |
Bool sd_mmc_mci_read_open (U8 slot, U32 pos, U16 nb_sector) | |
{ | |
U32 addr; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
// Set the global memory ptr at a Byte address. | |
gl_ptr_mem[slot] = pos ; | |
// wait for MMC not busy | |
mci_wait_busy_signal(mci); | |
addr = gl_ptr_mem[slot]; | |
// send command | |
if((!(SD_CARD_HC & g_u8_card_type[slot])) | |
&& (!(MMC_CARD_HC & g_u8_card_type[slot])) ) | |
{ | |
addr <<= 9; // For NO HC card the address must be translate in byte address | |
} | |
//** (CMD13) | |
// Necessary to clear flag error "ADDRESS_OUT_OF_RANGE" (ID LABO = MMC15) | |
if(mci_send_cmd(mci, SD_MMC_SEND_STATUS_CMD, g_u32_card_rca[slot])!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// Request Block Length | |
mci_set_block_size(mci, SD_MMC_SECTOR_SIZE); | |
// Set Block Count | |
mci_set_block_count(mci, nb_sector); | |
//** (CMD17) | |
if(mci_send_cmd(mci, SD_MMC_READ_MULTIPLE_BLOCK_CMD, addr)!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// check response | |
if ((mci_read_response(mci) & CS_FLAGERROR_RD_WR) != 0) | |
{ | |
return FALSE; | |
} | |
return TRUE; | |
} | |
Bool sd_mmc_mci_dma_read_open(U8 slot, U32 pos, void* ram, U16 nb_sector) | |
{ | |
U32 addr; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
// Set the global memory ptr at a Byte address. | |
gl_ptr_mem[slot] = pos ; | |
// wait for MMC not busy | |
mci_wait_busy_signal(mci); | |
addr = gl_ptr_mem[slot]; | |
// send command | |
if((!(SD_CARD_HC & g_u8_card_type[slot])) | |
&& (!(MMC_CARD_HC & g_u8_card_type[slot])) ) | |
{ | |
addr <<= 9; // For NO HC card the address must be translate in byte address | |
} | |
//** (CMD13) | |
// Necessary to clear flag error "ADDRESS_OUT_OF_RANGE" (ID LABO = MMC15) | |
if(mci_send_cmd(mci, SD_MMC_SEND_STATUS_CMD, g_u32_card_rca[slot])!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// Request Block Length | |
mci_set_block_size(mci, SD_MMC_SECTOR_SIZE); | |
// Set Block Count | |
mci_set_block_count(mci, nb_sector); | |
// Enable the DMACA | |
AVR32_DMACA.dmacfgreg = 1 << AVR32_DMACA_DMACFGREG_DMA_EN_OFFSET; | |
AVR32_MCI.dma = 0; | |
// Linked list ptrs: not used. | |
AVR32_DMACA.llp1 = 0x00000000; | |
// Channel 1 Ctrl register low | |
AVR32_DMACA.ctl1l = | |
(0 << AVR32_DMACA_CTL1L_INT_EN_OFFSET) | // Do not enable interrupts | |
(2 << AVR32_DMACA_CTL1L_DST_TR_WIDTH_OFFSET) | // Dst transfer width: 32 bits | |
(2 << AVR32_DMACA_CTL1L_SRC_TR_WIDTH_OFFSET) | // Src transfer width: 32 bits | |
(0 << AVR32_DMACA_CTL1L_DINC_OFFSET) | // Dst address increment: increment | |
(0 << AVR32_DMACA_CTL1L_SINC_OFFSET) | // Src address increment: increment | |
(3 << AVR32_DMACA_CTL1L_DST_MSIZE_OFFSET) | // Dst burst transaction len: 16 data items | |
(3 << AVR32_DMACA_CTL1L_SRC_MSIZE_OFFSET) | // Src burst transaction len: 16 data items | |
(0 << AVR32_DMACA_CTL1L_S_GATH_EN_OFFSET) | // Source gather: disabled | |
(0 << AVR32_DMACA_CTL1L_D_SCAT_EN_OFFSET) | // Destination scatter: disabled | |
(2 << AVR32_DMACA_CTL1L_TT_FC_OFFSET) | // transfer type:P2M, flow controller: DMACA | |
(1 << AVR32_DMACA_CTL1L_DMS_OFFSET) | // Dest master: HSB master 2 | |
(0 << AVR32_DMACA_CTL1L_SMS_OFFSET) | // Source master: HSB master 1 | |
(0 << AVR32_DMACA_CTL1L_LLP_D_EN_OFFSET) | // Not used | |
(0 << AVR32_DMACA_CTL1L_LLP_S_EN_OFFSET) // Not used | |
; | |
// Channel 1 Config register low | |
AVR32_DMACA.cfg1l = | |
(0 << AVR32_DMACA_CFG1L_HS_SEL_DST_OFFSET) | // Destination handshaking: ignored because the dst is memory. | |
(0 << AVR32_DMACA_CFG1L_HS_SEL_SRC_OFFSET) // Source handshaking: hw handshaking | |
; // All other bits set to 0. | |
// Channel 1 Config register high | |
AVR32_DMACA.cfg1h = | |
(0 << AVR32_DMACA_CFG1H_DEST_PER_OFFSET) | // Dest hw handshaking itf: ignored because the dst is memory. | |
(AVR32_DMACA_CH_MMCI_RX << AVR32_DMACA_CFG1H_SRC_PER_OFFSET) // Source hw handshaking itf: | |
; // All other bits set to 0. | |
// Setup MCI DMA register | |
AVR32_MCI.dma = AVR32_MCI_DMA_DMAEN_MASK | (AVR32_MCI_DMA_CHKSIZE_16_BYTES << AVR32_MCI_DMA_CHKSIZE_OFFSET); | |
//** (CMD17) | |
if(mci_send_cmd(mci, SD_MMC_READ_MULTIPLE_BLOCK_CMD, addr)!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// check response | |
if ((mci_read_response(mci) & CS_FLAGERROR_RD_WR) != 0) | |
{ | |
return FALSE; | |
} | |
return TRUE; | |
} | |
Bool sd_mmc_mci_read_close (U8 slot) | |
{ | |
if( (mci_crc_error(mci)) ) | |
{ | |
return FALSE; // An CRC error has been seen | |
} | |
mci_wait_busy_signal(mci); | |
if( mci_send_cmd( mci, SD_MMC_STOP_READ_TRANSMISSION_CMD, 0xffffffff ) != MCI_SUCCESS) | |
return FALSE; | |
/* | |
if( (mci_overrun_error(mci)) ) | |
{ | |
return FALSE; | |
} | |
if( (mci_underrun_error(mci)) ) | |
{ | |
return FALSE; | |
}*/ | |
return TRUE; | |
} | |
Bool sd_mmc_mci_write_open (U8 slot, U32 pos, U16 nb_sector) | |
{ | |
U32 addr; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci,slot,g_u8_card_bus_width[slot]); | |
// Set the global memory ptr at a Byte address. | |
gl_ptr_mem[slot] = pos ; | |
// wait for MMC not busy | |
mci_wait_busy_signal(mci); | |
/* | |
// (CMD13) | |
// Necessary to clear flag error "ADDRESS_OUT_OF_RANGE" (ID LABO = MMC15) | |
if( !mmc_drv_send_cmd( MMC_SEND_STATUS, g_u32_card_rca, MMC_RESP_R1 ) ) | |
{ | |
return FALSE; | |
} | |
mmc_drv_read_response(); | |
*/ | |
addr = gl_ptr_mem[slot]; | |
// send command | |
if((!(SD_CARD_HC & g_u8_card_type[slot])) | |
&& (!(MMC_CARD_HC & g_u8_card_type[slot])) ) | |
{ | |
addr <<= 9; // For NO HC card the address must be translate in byte address | |
} | |
// Set Block Length | |
mci_set_block_size(mci, SD_MMC_SECTOR_SIZE); | |
// Set Block Count | |
mci_set_block_count(mci, nb_sector); | |
//** (CMD24) | |
if(mci_send_cmd(mci, SD_MMC_WRITE_MULTIPLE_BLOCK_CMD, addr )!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// check response | |
if ((mci_read_response(mci) & CS_FLAGERROR_RD_WR) != 0) | |
{ | |
return FALSE; | |
} | |
return TRUE; | |
} | |
Bool sd_mmc_mci_dma_write_open (U8 slot, U32 pos, const void* ram, U16 nb_sector) | |
{ | |
U32 addr; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
// Set the global memory ptr at a Byte address. | |
gl_ptr_mem[slot] = pos ; | |
// wait for MMC not busy | |
mci_wait_busy_signal(mci); | |
/* | |
// (CMD13) | |
// Necessary to clear flag error "ADDRESS_OUT_OF_RANGE" (ID LABO = MMC15) | |
if( !mmc_drv_send_cmd( MMC_SEND_STATUS, g_u32_card_rca, MMC_RESP_R1 ) ) | |
{ | |
return FALSE; | |
} | |
mmc_drv_read_response(); | |
*/ | |
addr = gl_ptr_mem[slot]; | |
// send command | |
if((!(SD_CARD_HC & g_u8_card_type[slot])) | |
&& (!(MMC_CARD_HC & g_u8_card_type[slot])) ) | |
{ | |
addr <<= 9; // For NO HC card the address must be translate in byte address | |
} | |
// Set Block Length | |
mci_set_block_size(mci, SD_MMC_SECTOR_SIZE); | |
// Set Block Count | |
mci_set_block_count(mci, nb_sector); | |
// Enable the DMACA | |
AVR32_DMACA.dmacfgreg = 1 << AVR32_DMACA_DMACFGREG_DMA_EN_OFFSET; | |
AVR32_MCI.dma = 0; | |
// Linked list ptrs: not used. | |
AVR32_DMACA.llp1 = 0x00000000; | |
// Channel 1 Ctrl register low | |
AVR32_DMACA.ctl1l = | |
(0 << AVR32_DMACA_CTL1L_INT_EN_OFFSET) | // Do not enable interrupts | |
(2 << AVR32_DMACA_CTL1L_DST_TR_WIDTH_OFFSET) | // Dst transfer width: 32 bits | |
(2 << AVR32_DMACA_CTL1L_SRC_TR_WIDTH_OFFSET) | // Src transfer width: 32 bits | |
(0 << AVR32_DMACA_CTL1L_DINC_OFFSET) | // Dst address increment: increment | |
(0 << AVR32_DMACA_CTL1L_SINC_OFFSET) | // Src address increment: increment | |
(3 << AVR32_DMACA_CTL1L_DST_MSIZE_OFFSET) | // Dst burst transaction len: 16 data items | |
(3 << AVR32_DMACA_CTL1L_SRC_MSIZE_OFFSET) | // Src burst transaction len: 16 data items | |
(0 << AVR32_DMACA_CTL1L_S_GATH_EN_OFFSET) | // Source gather: disabled | |
(0 << AVR32_DMACA_CTL1L_D_SCAT_EN_OFFSET) | // Destination scatter: disabled | |
(1 << AVR32_DMACA_CTL1L_TT_FC_OFFSET) | // transfer type:M2P, flow controller: DMACA | |
(0 << AVR32_DMACA_CTL1L_DMS_OFFSET) | // Dest master: HSB master 1 | |
(1 << AVR32_DMACA_CTL1L_SMS_OFFSET) | // Source master: HSB master 2 | |
(0 << AVR32_DMACA_CTL1L_LLP_D_EN_OFFSET) | // Not used | |
(0 << AVR32_DMACA_CTL1L_LLP_S_EN_OFFSET) // Not used | |
; | |
// Channel 1 Config register low | |
AVR32_DMACA.cfg1l = | |
(0 << AVR32_DMACA_CFG1L_HS_SEL_DST_OFFSET) | // Destination handshaking: hw handshaking | |
(0 << AVR32_DMACA_CFG1L_HS_SEL_SRC_OFFSET) // Source handshaking: ignored because the dst is memory. | |
; // All other bits set to 0. | |
// Channel 1 Config register high | |
AVR32_DMACA.cfg1h = | |
(AVR32_DMACA_CH_MMCI_TX << AVR32_DMACA_CFG1H_DEST_PER_OFFSET) | // Dest hw handshaking itf: | |
(0 << AVR32_DMACA_CFG1H_SRC_PER_OFFSET) // Source hw handshaking itf: ignored because the dst is memory. | |
; // All other bits set to 0. | |
// Setup MCI DMA register | |
AVR32_MCI.dma = AVR32_MCI_DMA_DMAEN_MASK | (AVR32_MCI_DMA_CHKSIZE_16_BYTES << AVR32_MCI_DMA_CHKSIZE_OFFSET); | |
//** (CMD24) | |
if(mci_send_cmd(mci, SD_MMC_WRITE_MULTIPLE_BLOCK_CMD, addr )!=MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
// check response | |
if ((mci_read_response(mci) & CS_FLAGERROR_RD_WR) != 0) | |
{ | |
return FALSE; | |
} | |
return TRUE; | |
} | |
Bool sd_mmc_mci_write_close (U8 slot) | |
{ | |
if( (mci_crc_error(mci)) ) | |
{ | |
return FALSE; // An CRC error has been seen | |
} | |
while(!(mci_data_block_ended(mci))); | |
if( mci_send_cmd( mci, SD_MMC_STOP_WRITE_TRANSMISSION_CMD, 0xffffffff ) != MCI_SUCCESS) | |
{ | |
return FALSE; | |
} | |
/* | |
if( (mci_overrun_error(mci)) ) | |
{ | |
return FALSE; | |
} | |
if( (mci_underrun_error(mci)) ) | |
{ | |
return FALSE; | |
}*/ | |
if( slot==SD_SLOT_4BITS ) | |
{ | |
while(!(gpio_get_pin_value(SD_SLOT_4BITS_DATA0_PIN))); // Wait until the card is ready. | |
} | |
else | |
{ | |
while(!(gpio_get_pin_value(SD_SLOT_8BITS_DATA0_PIN))); // Wait until the card is ready. | |
} | |
return TRUE; | |
} | |
#if ACCESS_USB == ENABLED | |
#ifdef USB_DEVICE_VENDOR_ID | |
// USB Device Stack V2 | |
#include "udi_msc.h" | |
Bool sd_mmc_mci_read_multiple_sector(U8 slot, U16 nb_sector) | |
{ | |
Bool b_first_step=TRUE; | |
U8 buffer_id=0; | |
// Pipeline the 2 DMA transfer in order to speed-up the performances: | |
// DMA MCI -> RAM | |
// DMA RAM -> USB | |
// | |
while (nb_sector--) { | |
// (re)load first stage. | |
dma_mci_2_ram((0==(buffer_id++%2))?§or_buf_0:§or_buf_1, SD_MMC_SECTOR_SIZE); | |
// (re)load second stage. | |
if( !b_first_step ) { | |
if (!udi_msc_trans_block(true, (0==(buffer_id%2))?sector_buf_0:sector_buf_1, SD_MMC_SECTOR_SIZE, NULL)) { | |
return FALSE; | |
} | |
} | |
b_first_step = FALSE; | |
// Wait completion of DMACA stage. | |
while( !is_dma_mci_2_ram_complete() ); | |
} | |
// Complete execution of the last transfer (which is in the pipe). | |
if (!udi_msc_trans_block(true, (0!=(buffer_id%2))?sector_buf_0:sector_buf_1, SD_MMC_SECTOR_SIZE, NULL)) | |
return FALSE; | |
return TRUE; | |
} | |
Bool sd_mmc_mci_write_multiple_sector(U8 slot, U16 nb_sector) | |
{ | |
Bool b_first_step=TRUE; | |
uint8_t buffer_id=0; | |
// Pipeline the 2 DMA transfer in order to speed-up the performances: | |
// DMA USB -> RAM | |
// DMA RAM -> MCI | |
// | |
while (nb_sector--) { | |
// (re)load second stage. | |
if( !b_first_step ) { | |
dma_ram_2_mci((0!=(buffer_id%2))?§or_buf_0:§or_buf_1, SD_MMC_SECTOR_SIZE); | |
} | |
udi_msc_trans_block(false, (0==(buffer_id++%2))?sector_buf_0:sector_buf_1, SD_MMC_SECTOR_SIZE, NULL); | |
if( !b_first_step ) { | |
// Wait completion of DMACA stage. | |
while( !is_dma_ram_2_mci_complete() ); | |
} | |
b_first_step=FALSE; | |
} | |
// Complete execution of the last transfer (which is in the pipe). | |
dma_ram_2_mci((0!=(buffer_id%2))?§or_buf_0:§or_buf_1, SD_MMC_SECTOR_SIZE); | |
while( !is_dma_ram_2_mci_complete() ); | |
return TRUE; | |
} | |
#else | |
// USB Device Stack V1 | |
#include "usb_drv.h" | |
#include "scsi_decoder.h" | |
Bool sd_mmc_mci_read_multiple_sector(U8 slot, U16 nb_sector) | |
{ | |
Bool b_last_state_full=FALSE; | |
U8 buffer_id=0; | |
// Turn on features used by the DMA-USB. | |
Usb_enable_endpoint_bank_autoswitch(g_scsi_ep_ms_in); | |
// Pipeline the 2 DMA transfer in order to speed-up the performances: | |
// DMA MCI -> RAM | |
// DMA RAM -> USB | |
// | |
while (nb_sector--) { | |
// (re)load first stage. | |
if( buffer_id==0 ) { | |
dma_mci_2_ram(§or_buf_0, SD_MMC_SECTOR_SIZE); | |
buffer_id=1; | |
} else { | |
dma_mci_2_ram(§or_buf_1, SD_MMC_SECTOR_SIZE); | |
buffer_id=0; | |
} | |
// (re)load second stage. | |
if( b_last_state_full ) { | |
if( buffer_id==0 ) { | |
dma_ram_2_usb(§or_buf_0, SD_MMC_SECTOR_SIZE); | |
} else { | |
dma_ram_2_usb(§or_buf_1, SD_MMC_SECTOR_SIZE); | |
} | |
// Wait completion of both stages. | |
while( !is_dma_mci_2_ram_complete() ); | |
while( !is_dma_ram_2_usb_complete() ); | |
} else { | |
b_last_state_full=TRUE; | |
// Wait completion of first stage only. | |
while( !is_dma_mci_2_ram_complete() ); | |
} | |
} | |
// Complete execution of the last transfer (which is in the pipe). | |
if( buffer_id==0 ) { | |
dma_ram_2_usb(§or_buf_1, SD_MMC_SECTOR_SIZE); | |
} else { | |
dma_ram_2_usb(§or_buf_0, SD_MMC_SECTOR_SIZE); | |
} | |
while( !is_dma_ram_2_usb_complete() ); | |
// Wait until the USB RAM is empty before disabling the autoswitch feature. | |
while( Usb_nb_busy_bank(g_scsi_ep_ms_in)!=0 ); | |
// Turn off exotic USB features that may not work for other devices (at45dbx...) | |
Usb_disable_endpoint_bank_autoswitch(g_scsi_ep_ms_in); | |
return TRUE; | |
} | |
Bool sd_mmc_mci_write_multiple_sector(U8 slot, U16 nb_sector) | |
{ | |
Bool b_last_state_full=FALSE; | |
U8 buffer_id=0; | |
// Turn on features used by the DMA-USB. | |
Usb_enable_endpoint_bank_autoswitch(g_scsi_ep_ms_out); | |
// Pipeline the 2 DMA transfer in order to speed-up the performances: | |
// DMA USB -> RAM | |
// DMA RAM -> MCI | |
// | |
while (nb_sector--) { | |
// (re)load first stage. | |
if( buffer_id==0 ) { | |
dma_usb_2_ram(§or_buf_0, SD_MMC_SECTOR_SIZE); | |
buffer_id=1; | |
} else { | |
dma_usb_2_ram(§or_buf_1, SD_MMC_SECTOR_SIZE); | |
buffer_id=0; | |
} | |
// (re)load second stage. | |
if( b_last_state_full ) { | |
if( buffer_id==0 ) { | |
dma_ram_2_mci(§or_buf_0, SD_MMC_SECTOR_SIZE); | |
} else { | |
dma_ram_2_mci(§or_buf_1, SD_MMC_SECTOR_SIZE); | |
} | |
// Wait completion of both stages. | |
while( !is_dma_usb_2_ram_complete() ); | |
while( !is_dma_ram_2_mci_complete() ); | |
} else { | |
b_last_state_full=TRUE; | |
// Wait completion of the first stage only. | |
while( !is_dma_usb_2_ram_complete() ); | |
} | |
} | |
// Complete execution of the last transfer (which is in the pipe). | |
if( buffer_id==0 ) { | |
dma_ram_2_mci(§or_buf_1, SD_MMC_SECTOR_SIZE); | |
} else { | |
dma_ram_2_mci(§or_buf_0, SD_MMC_SECTOR_SIZE); | |
} | |
while( !is_dma_ram_2_mci_complete() ); | |
// Wait until the USB RAM is empty before disabling the autoswitch feature. | |
while( Usb_nb_busy_bank(g_scsi_ep_ms_out)!=0 ); | |
// Turn off exotic USB features that may not work for other devices (at45dbx...) | |
Usb_disable_endpoint_bank_autoswitch(g_scsi_ep_ms_out); | |
return TRUE; | |
} | |
#endif | |
#endif | |
#if (defined MMC_CARD_SECU_FUNC) && (MMC_CARD_SECU_FUNC == ENABLE) | |
Bool sd_mmc_mci_lock_unlock (U8 slot, U8 cmd, U8 pwd_len, U8 * password) // password length in Bytes (possible values : 2,6,14) | |
{ | |
U8 block_count; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
// Wait Busy Signal | |
mci_wait_busy_signal(mci); | |
if (FALSE == sd_mmc_set_block_len (slot, (U8) pwd_len+2)) | |
{ | |
return FALSE; | |
} | |
// Send Lock/Unlock Command | |
mci_send_cmd(mci, SD_MMC_LOCK_UNLOCK, 0); | |
// check response | |
if ((mci_read_response(mci) & MMC_TRAN_STATE_MSK) != MMC_TRAN_STATE) | |
{ | |
return FALSE; | |
} | |
// Sends the command | |
mci_wr_data(mci, cmd); | |
// Sends the data | |
if (cmd != CMD_FULL_ERASE) | |
{ | |
mci_wr_data(mci, pwd_len); // PWD_LENGTH | |
} | |
for ( block_count = 0 ; block_count < pwd_len ; block_count++) //PWD | |
{ | |
mci_wr_data(mci, *(password+block_count)); | |
} | |
sd_mmc_set_block_len(slot,SD_MMC_SECTOR_SIZE); | |
return TRUE; | |
} | |
Bool is_sd_mmc_mci_locked(U8 slot) | |
{ | |
U32 response; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
// ask status | |
if (sd_mmc_mci_cmd_send_status(slot)==FALSE) | |
return TRUE; | |
response = mci_read_response(mci); | |
if ((((U8)(response>>24))&0x02)!=0x00) | |
{ // Then it is locked | |
return TRUE; | |
} | |
return FALSE; | |
} | |
Bool sd_mmc_mci_lock_unlock_failed(U8 slot) | |
{ | |
U32 response; | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
// ask status | |
if (sd_mmc_mci_cmd_send_status(slot)==FALSE) | |
return TRUE; | |
response = mci_read_response(mci); | |
if ((((Byte)(response>>24))&0x01)!=0x00) | |
{ // Then it failed | |
return FALSE; | |
} | |
return TRUE; | |
} | |
#endif // end FUNC_MMC_CARD_SECU | |
Bool sd_mmc_mci_cmd_send_status(U8 slot) | |
{ | |
if (slot > MCI_LAST_SLOTS) | |
return FALSE; | |
// Select Slot card before any other command. | |
mci_select_card(mci, slot, g_u8_card_bus_width[slot]); | |
if (mci_send_cmd(mci, SD_MMC_SEND_STATUS_CMD, g_u32_card_rca[slot])!=MCI_SUCCESS) | |
return FALSE; | |
return TRUE; | |
} | |
#endif // SD_MMC_MCI_0_MEM == ENABLE || SD_MMC_MCI_1_MEM == ENABLE |