blob: 98fb71e83eb2e78bbcb66c5926f5d9ce31997e9b [file] [log] [blame]
/*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))?&sector_buf_0:&sector_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))?&sector_buf_0:&sector_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))?&sector_buf_0:&sector_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(&sector_buf_0, SD_MMC_SECTOR_SIZE);
buffer_id=1;
} else {
dma_mci_2_ram(&sector_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(&sector_buf_0, SD_MMC_SECTOR_SIZE);
} else {
dma_ram_2_usb(&sector_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(&sector_buf_1, SD_MMC_SECTOR_SIZE);
} else {
dma_ram_2_usb(&sector_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(&sector_buf_0, SD_MMC_SECTOR_SIZE);
buffer_id=1;
} else {
dma_usb_2_ram(&sector_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(&sector_buf_0, SD_MMC_SECTOR_SIZE);
} else {
dma_ram_2_mci(&sector_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(&sector_buf_1, SD_MMC_SECTOR_SIZE);
} else {
dma_ram_2_mci(&sector_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