summaryrefslogtreecommitdiff
path: root/board/st/u8500/mmc_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/st/u8500/mmc_utils.c')
-rw-r--r--board/st/u8500/mmc_utils.c1022
1 files changed, 1022 insertions, 0 deletions
diff --git a/board/st/u8500/mmc_utils.c b/board/st/u8500/mmc_utils.c
new file mode 100644
index 000000000..a9119f883
--- /dev/null
+++ b/board/st/u8500/mmc_utils.c
@@ -0,0 +1,1022 @@
+/*
+ * (C) Copyright 2009
+ * ST-Ericsson, <www.stericsson.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <linux/ctype.h>
+
+#include <common.h>
+#include <command.h>
+#include "gpio.h"
+#include "mmc.h" // MMC api
+#include "mmc_utils.h" // to access MMC
+#include "mmc_p.h" // t_mmc_register definition
+
+u32 MMCBuffer[1024] ;
+static int IS_SD_CARD;
+
+/* --- exported from other modules ---------------------------------------- */
+static u8 selected_card = 0;
+extern t_mmc_error mmc_cmderror_2 (void);
+extern t_mmc_error mmc_cmdresp2error_2 (void);
+extern t_mmc_error mmc_cmdresp3error_2 (void);
+extern t_mmc_error mmc_cmdresp145error_2 (u8 cmd);
+extern t_mmc_error mmc_cmdreadresp (u32 * tempbuff);
+extern t_mmc_error mmc_waitcmdreadresp (void);
+extern t_mmc_error mmc_cmdwriteresp (u8 cardno, u32 * tempbuff, u16 total_num_of_bytes);
+extern t_mmc_error mmc_waitcmdwriteresp (u8 cardno, u32 * tempbuff, u16 total_num_of_bytes);
+
+extern t_mmc_register *t_mmc0;
+extern u32 t_mmc_rel_addr;
+
+t_mmc_boot_record mmc_boot_record;
+
+void mmc_copyByteH (u8 * sourceAddr, u8 * destAddress, int size)
+{
+ int i;
+ for (i = 0; i < size; i++)
+ {
+ *(destAddress + i) = *(sourceAddr + i);
+ }
+}
+
+void mmc_shift_memH (int num_of_words, u32 * start_address, u32 * dest_address, u32 shift)
+{
+ u32 *address;
+ int word = 0;
+ u32 high;
+ int i, word_offset, bit_offset;
+
+ word_offset = (int) (shift / 32);
+ bit_offset = (int) (shift % 32);
+ for (i = 0; i < num_of_words; i++)
+ {
+ *(dest_address + i) = 0;
+ }
+ for (i = word_offset; i < num_of_words; i++)
+ {
+ *(dest_address + i - word_offset) = *(start_address + i);
+ }
+ address = dest_address;
+ for (word = 0; word < num_of_words - 1; word++)
+ {
+ *address = (*address) >> bit_offset;
+ address++;
+ high = (*address << (32 - bit_offset));
+ *(address - 1) |= high;
+ }
+ *address = (*address) >> bit_offset;
+}
+
+u8 convert_from_bytes_to_power_of_two (u16 no_of_bytes)
+{
+ u8 count = 0;
+ while (no_of_bytes != 1)
+ {
+ no_of_bytes >>= 1;
+ count++;
+ }
+ return count;
+}
+
+t_mmc_error mmc_enable ()
+{
+ t_mmc_error error = MMC_OK;
+ t_mmc_command_control commcontrol;
+ t_bool validvoltage = FALSE;
+ u32 arg, response;
+ int i;
+
+ IS_SD_CARD = 0;
+
+ selected_card = 0;
+
+ t_mmc0->mmc_Power = 0x1BF;
+ t_mmc0->mmc_Clock = 0x41FF;
+
+ commcontrol.IsRespExpected = FALSE;
+ commcontrol.IsLongResp = FALSE;
+ commcontrol.IsInterruptMode = FALSE;
+ commcontrol.IsPending = FALSE;
+ commcontrol.cmdpath = MMC_ENABLE;
+
+ error = mmc_sendcommand (MMC_GO_IDLE_STATE, 0x00000000, commcontrol);
+
+ error = mmc_cmderror_2 ();
+
+ //// Added by Chris Sebastian for SD Card support:
+ //// Send ACMD41. If we do not get a response, it is not an SD card.
+ //// If we do get a response, loop until card is not busy.
+
+ commcontrol.IsRespExpected = TRUE;
+ commcontrol.IsLongResp = FALSE;
+ commcontrol.IsInterruptMode = FALSE;
+ commcontrol.IsPending = FALSE;
+ commcontrol.cmdpath = MMC_ENABLE;
+
+ for(i = 200; i; i--) {
+ error = mmc_sendcommand (MMC_APP_CMD, 0x00000000, commcontrol); // Let the card know that the next command is an app-cmd.
+ error = mmc_cmdresp145error_2(MMC_APP_CMD);
+ error = mmc_sendcommand (SD_SEND_OP_COND, 0x00060000, commcontrol); // I got the 0x00060000 from Linux kernel source.
+ error = mmc_cmdresp3error_2 ();
+ t_mmc0->mmc_Clear = ClrStaticFlags; //clear all the static status flags. CmdResp3Error_2 leaves some bits set.
+ if (t_mmc0->mmc_Response0 & 0x80000000) {
+ printf("SD card detected \n");
+ IS_SD_CARD = 1;
+ return MMC_OK; // SD CARD DETECTED. Do not continue with MMC init logic. Quick escape!
+ }
+ }
+
+ commcontrol.IsRespExpected = FALSE;
+ commcontrol.IsLongResp = FALSE;
+ commcontrol.IsInterruptMode = FALSE;
+ commcontrol.IsPending = FALSE;
+ commcontrol.cmdpath = MMC_ENABLE;
+
+ error = mmc_sendcommand (MMC_GO_IDLE_STATE, 0x00000000, commcontrol);
+ error = mmc_cmderror_2 ();
+
+ arg = 0x00060000; // High Voltage MMC, byte mode. Was 0x00FFC000, but that writes to reserved bits...
+ while (!validvoltage)
+ {
+ // send CMD1 (SEND_OP_COND)
+ commcontrol.IsRespExpected = TRUE;
+ error = mmc_sendcommand (MMC_SEND_OP_COND, arg, commcontrol);
+
+ error = mmc_cmdresp3error_2 ();
+
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ mmc_getresponse (MMC_SHORT_RESP, &response);
+
+ arg = response;
+ validvoltage = (t_bool) (((response >> 31) == 1) ? 1 : 0);
+
+ }
+end:
+ return error;
+}
+
+t_mmc_error mmc_disable ()
+{
+ t_mmc_error error = MMC_OK;
+ t_mmc_power_state powerstate = MMC_POWER_OFF;
+
+ error = mmc_setpowerstate (powerstate);
+ return error;
+}
+
+t_mmc_error mmc_initCard ()
+{
+ t_mmc_error error = MMC_OK;
+ t_mmc_command_control commcontrol;
+ t_mmc_bus_configuration busconfig;
+ t_mmc_clock_control clockcontrol;
+
+ // send CMD2 (ALL_SEND_CID)
+ commcontrol.IsRespExpected = TRUE;
+ commcontrol.IsLongResp = TRUE;
+ commcontrol.IsInterruptMode = FALSE;
+ commcontrol.IsPending = FALSE;
+ commcontrol.cmdpath = MMC_ENABLE;
+
+ error = mmc_sendcommand (MMC_ALL_SEND_CID, 0x00000000, commcontrol);
+ error = mmc_cmdresp2error_2 ();
+ // error is MMC_CMD_CRC_FAIL on COB board ?!
+ // if( error != MMC_OK)
+ // goto end;
+
+ // send CMD3 (SET_RELATIVE_ADDR)
+
+ commcontrol.IsLongResp = FALSE;
+ error = mmc_sendcommand (MMC_SET_REL_ADDR, t_mmc_rel_addr, commcontrol);
+ error = mmc_cmdresp145error_2 (MMC_SET_REL_ADDR);
+ if(IS_SD_CARD) {
+ t_mmc_rel_addr = t_mmc0->mmc_Response0 & 0xFFFF0000;
+ }
+
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ busconfig.mode = MMC_PUSH_PULL;
+ busconfig.rodctrl = MMC_DISABLE;
+ error = mmc_configbus (busconfig);
+ clockcontrol.pwrsave= MMC_DISABLE;
+ clockcontrol.bypass = MMC_DISABLE;
+ clockcontrol.widebus= MMC_DISABLE;
+ error = mmc_setclockfrequency(0x00); /* 26 MHz */
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ error = mmc_configclockcontrol (clockcontrol);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+end:
+ return error;
+}
+
+t_mmc_error mmc_readblock (u8 cardno, u32 addr, u32 * readbuff, u16 blocksize, t_mmc_transfer_mode mmc_transfer_mode)
+{
+ t_mmc_error error = MMC_OK;
+ u8 power;
+ t_mmc_command_control commcontrol;
+ u32 response;
+
+ commcontrol.IsRespExpected = TRUE ;
+ commcontrol.IsLongResp = FALSE ;
+ commcontrol.IsInterruptMode = FALSE ;
+ commcontrol.IsPending = FALSE ;
+ commcontrol.cmdpath = MMC_ENABLE ;
+ error = mmc_setdatapath (MMC_DISABLE);
+ error = mmc_handledma (MMC_DISABLE);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ // send command for selecting the card
+ if (cardno != selected_card)
+ {
+ error = mmc_sendcommand (MMC_SEL_DESEL_CARD, t_mmc_rel_addr, commcontrol);
+ error = mmc_cmdresp145error_2 (MMC_SEL_DESEL_CARD);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ else
+ {
+ selected_card = cardno;
+ }
+ }
+ error = mmc_getresponse (MMC_SHORT_RESP, &response);
+ if (response & 0x02000000)
+ {
+ return MMC_LOCK_UNLOCK_FAILED;
+ }
+ // set the block size,both on controller and card
+ if ((blocksize > 0) && (blocksize <= 2048) && ((blocksize & (blocksize - 1)) == 0))
+ {
+ power = convert_from_bytes_to_power_of_two (blocksize);
+ error = mmc_setdatablocklength (power);
+ error = mmc_sendcommand (MMC_SET_BLOCKLEN, (u32) blocksize, commcontrol);
+ error = mmc_cmdresp145error_2 (MMC_SET_BLOCKLEN);
+ if (error != MMC_OK)
+ {
+ return error;
+ }
+ }
+ else
+ {
+ error = MMC_INVALID_PARAMETER;
+ goto end;
+ }
+ error = mmc_setdatalength (blocksize );
+ error = mmc_setdatatimeout (0xefffffff );
+ error = mmc_settransferdirection (MMC_READ );
+ error = mmc_settransfertype (MMC_BLOCK );
+ error = mmc_setdatapath (MMC_ENABLE);
+ //t_mmc0->mmc_DataCtrl |= (ReadDir & ~StreamMode) | DataPathEnable;
+ error = mmc_sendcommand (MMC_READ_SINGLE_BLOCK, addr, commcontrol);
+ error = mmc_cmdresp145error_2 (MMC_READ_SINGLE_BLOCK);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ if (mmc_transfer_mode == MMCDMA)
+ {
+ error = mmc_waitcmdreadresp ();
+ }
+ else
+ {
+ error = mmc_cmdreadresp (readbuff);
+ }
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+end:
+ return error;
+}
+
+t_mmc_error mmc_writeblock (u8 cardno, u32 addr, u32 * writebuff, u16 blocksize, t_mmc_transfer_mode mmc_transfer_mode)
+{
+ t_mmc_error error = MMC_OK;
+ u8 power;
+ t_mmc_command_control commcontrol;
+ u32 response;
+
+ commcontrol.IsRespExpected = TRUE;
+ commcontrol.IsLongResp = FALSE;
+ commcontrol.IsInterruptMode = FALSE;
+ commcontrol.IsPending = FALSE;
+ commcontrol.cmdpath = MMC_ENABLE;
+
+ error = mmc_setdatapath (MMC_DISABLE);
+ error = mmc_handledma (MMC_DISABLE);
+ error = mmc_settransferdirection(MMC_WRITE);
+ error = mmc_settransfertype (MMC_BLOCK);
+
+ if (cardno != selected_card)
+ {
+ error = mmc_sendcommand (MMC_SEL_DESEL_CARD, t_mmc_rel_addr, commcontrol);
+ error = mmc_cmdresp145error_2 (MMC_SEL_DESEL_CARD);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ else
+ {
+ selected_card = cardno;
+ }
+ }
+
+ mmc_getresponse (MMC_SHORT_RESP, &response);
+ if (response & 0x02000000)
+ {
+ return MMC_LOCK_UNLOCK_FAILED;
+ }
+ // set the block size,both on controller and card
+ if ((blocksize > 0) && (blocksize <= 2048) && (((blocksize & (blocksize - 1)) == 0)))
+ {
+ power = convert_from_bytes_to_power_of_two (blocksize);
+ error = mmc_setdatablocklength (power);
+ error = mmc_sendcommand (MMC_SET_BLOCKLEN, (u32) blocksize, commcontrol);
+ error = mmc_cmdresp145error_2 (MMC_SET_BLOCKLEN);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ }
+ else
+ {
+ error = MMC_INVALID_PARAMETER;
+ goto end;
+ }
+
+ error = mmc_setdatalength (blocksize);
+ error = mmc_setdatatimeout (0xefffffff);
+ error = mmc_settransferdirection (MMC_WRITE);
+ error = mmc_settransfertype (MMC_BLOCK);
+ error = mmc_setdatapath (MMC_ENABLE);
+ error = mmc_sendcommand (MMC_WRITE_SINGLE_BLOCK, addr, commcontrol);
+ error = mmc_cmdresp145error_2 (MMC_WRITE_SINGLE_BLOCK);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ if (mmc_transfer_mode == MMCDMA)
+ {
+ error = mmc_waitcmdwriteresp (cardno, writebuff, blocksize);
+ }
+ else
+ {
+ error = mmc_cmdwriteresp (cardno, writebuff, blocksize);
+ }
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+end:
+ return error;
+}
+
+t_mmc_error mmc_readcsd (u32 * CSD)
+{
+ t_mmc_error error = MMC_OK;
+ t_mmc_command_control commcontrol;
+ u32 buf[4];
+
+ // send CMD9 (SEND CSD)
+ commcontrol.IsRespExpected = TRUE;
+ commcontrol.IsLongResp = TRUE;
+ commcontrol.IsInterruptMode = FALSE;
+ commcontrol.IsPending = FALSE;
+ commcontrol.cmdpath = MMC_ENABLE;
+
+ error = mmc_sendcommand (MMC_SEND_CSD, t_mmc_rel_addr, commcontrol);
+ error = mmc_cmdresp2error_2 ();
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ error = mmc_getresponse (MMC_LONG_RESP, buf);
+ CSD[0] = buf[3];
+ CSD[1] = buf[2];
+ CSD[2] = buf[1];
+ CSD[3] = buf[0];
+end:
+ return error;
+}
+
+t_mmc_error mmc_select_n_switch ()
+{
+ t_mmc_error error = MMC_OK;
+ t_mmc_command_control commcontrol;
+ t_mmc_clock_control clockcontrol;
+ u32 response;
+ u8 cardno = 1;
+
+ commcontrol.IsRespExpected = TRUE;
+ commcontrol.IsLongResp = FALSE;
+ commcontrol.IsInterruptMode = FALSE;
+ commcontrol.IsPending = FALSE;
+ commcontrol.cmdpath = MMC_ENABLE;
+
+ // send command for selecting the card
+ if (cardno != selected_card)
+ {
+ error = mmc_sendcommand (MMC_SEL_DESEL_CARD, t_mmc_rel_addr, commcontrol);
+ error = mmc_cmdresp145error_2 (MMC_SEL_DESEL_CARD);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ else
+ {
+ selected_card = cardno;
+ }
+ }
+ error = mmc_getresponse (MMC_SHORT_RESP, &response);
+ if (response & 0x02000000)
+ {
+ error = MMC_LOCK_UNLOCK_FAILED;
+ goto end;
+ }
+ /*
+ error = mmc_sendcommand (MMC_APP_CMD, 0x00000000, commcontrol);
+ error = mmc_cmdresp145error_2(MMC_APP_CMD);
+ error = mmc_sendcommand (6, 0x2, commcontrol);
+ error = mmc_cmdresp145error_2(6);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ clockcontrol.pwrsave= MMC_DISABLE;
+ clockcontrol.bypass = MMC_DISABLE;
+ clockcontrol.widebus= MMC_ENABLE;
+ error = mmc_configclockcontrol (clockcontrol);
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ */
+end:
+ return error;
+}
+
+t_mmc_error mmc_readcid (u32 * CID)
+{
+ t_mmc_error error = MMC_OK;
+ t_mmc_command_control commcontrol;
+ u32 buf[4];
+
+ // send CMD9 (SEND CSD)
+ commcontrol.IsRespExpected = TRUE;
+ commcontrol.IsLongResp = TRUE;
+ commcontrol.IsInterruptMode = FALSE;
+ commcontrol.IsPending = FALSE;
+ commcontrol.cmdpath = MMC_ENABLE;
+
+ error = mmc_sendcommand (MMC_SEND_CID, t_mmc_rel_addr, commcontrol);
+ error = mmc_cmdresp2error_2 ();
+ if (error != MMC_OK)
+ {
+ goto end;
+ }
+ error = mmc_getresponse (MMC_LONG_RESP, buf);
+ CID[0] = buf[3];
+ CID[1] = buf[2];
+ CID[2] = buf[1];
+ CID[3] = buf[0];
+end:
+ return error;
+}
+
+t_mmc_error mmc_read_file (char *filename, u32 address, u32 * FileSize)
+{
+ u8 *mem_address = (u8 *) address;
+ u8 sector[512];
+ u16 BytesPerSector;
+ u32 BRStartSector;
+ u32 FATStartSector;
+ u32 DataStartSector;
+ u32 FileStartSector;
+ u16 SectorsPerFAT;
+ u8 SectorsPerCluster;
+ u8 k;
+ u16 MaxRDEntries;
+ u16 ReservedSectors;
+ u32 RDStartSector, j;
+ char nomefile[12] = " ";
+ int filelength;
+ u16 FileStartCluster = 0;
+ t_mmc_error response, response2;
+ int i, goout, found, result = PASS;
+ u32 CSD[4];
+ char mmcfilename[] = " ";
+ char *dotpos;
+
+ /////////// Attention please: /////////////////////
+ // //
+ // if other Alternate function apart from MMCI //
+ // are selected, the MMCI I/F has some problems //
+ // //
+ ////////////////////////////////////////////////////
+
+ gpio_altfuncenable(GPIO_ALT_SD_CARD0, "MMC");
+ // Power-on the controller
+ response = mmc_enable ();
+
+ if (response != MMC_OK)
+ {
+
+ response = mmc_enable (); // This actually IS necessary because it takes time for newly-inserted cards initialize. ~Chris S.
+ if (response != MMC_OK)
+ {
+ printf ("Error in card power on\n");
+ result = FAIL;
+ goto end;
+ }
+ }
+ // Initialise the cards on the bus, if any
+ response = mmc_initCard ();
+
+ if (response != MMC_OK)
+ {
+ printf ("Error in card initialization\n");
+ result = FAIL;
+ goto end;
+ }
+ // Get card info: CID, CSD, RCA registers
+ response = mmc_readcsd (CSD);
+
+ if (response != MMC_OK)
+ {
+ printf ("Error while fetching card info\n");
+ result = FAIL;
+ goto end;
+ }
+
+ // Select card and switch to 4-Bit, TODO HS if possible
+ response = mmc_select_n_switch ();
+
+ if (response != MMC_OK)
+ {
+ printf ("Error while select or switching to 4-bit/HS\n");
+ goto end;
+ }
+
+ // Read the MBR
+ response = mmc_readblock (1, 0, (u32 *) sector, 512, MMCPOLLING);
+
+ if (response != MMC_OK)
+ {
+ printf ("Error while reading boot record\n");
+ result = FAIL;
+ goto end;
+ }
+ if (sector[446] == 0x00 || sector[446] == 0x80)
+ { // found a MBR at the beginning of card
+ BRStartSector = sector[454];
+ }
+ else
+ { // BR at the beginning of card
+ BRStartSector = 0x00;
+ }
+ // Read the BR
+ response = mmc_readblock (1, (u32) (512 * BRStartSector), (u32 *) & mmc_boot_record, 512, MMCPOLLING);
+
+ k = 0;
+ while (response == MMC_DATA_CRC_FAIL && (k < 2))
+ {
+ response = mmc_readblock (1, (u32) (512 * BRStartSector), (u32 *) & mmc_boot_record, 512, MMCPOLLING);
+ k++;
+ }
+ if (response != MMC_OK)
+ {
+ printf ("Error while reading boot record\n");
+ result = FAIL;
+ goto end;
+ }
+ mmc_copyByteH (mmc_boot_record.BytesPerSector, (u8 *) & BytesPerSector, 2);
+ mmc_copyByteH (mmc_boot_record.ReservedSectors, (u8 *) & ReservedSectors, 2);
+ FATStartSector = BRStartSector + ReservedSectors; // the field at offset 15 contains the number of reserved sectors at
+ // the beginning of the media including the boot sector
+ mmc_copyByteH (mmc_boot_record.SectorsPerFat, (u8 *) & SectorsPerFAT, 2);
+ SectorsPerCluster = mmc_boot_record.SectorsPerCluster[0];
+ mmc_copyByteH (mmc_boot_record.NumOfRootEntries, (u8 *) & MaxRDEntries, 2);
+ FATStartSector += SectorsPerFAT;
+ RDStartSector = FATStartSector + SectorsPerFAT;
+ DataStartSector = RDStartSector + (u32) ((MaxRDEntries * 32) / 512);
+
+
+
+ // convert filename into mmc compatible file name (upper case , <= 8+3 char, no dot, no extension)
+ filelength = strlen (filename);
+ dotpos = strchr (filename, '.');
+ if (dotpos == NULL)
+ {
+ // no dot
+ if (filelength <= 8)
+ {
+ for (j = 0; j < filelength; j++)
+ {
+ mmcfilename[j] = (char) toupper (filename[j]);
+ }
+ }
+ else
+ {
+ for (j = 0; j < 6; j++)
+ {
+ mmcfilename[j] = (char) toupper (filename[j]);
+ }
+ mmcfilename[7] = '~';
+ mmcfilename[8] = '1';
+ filelength = 8;
+ }
+ }
+ else
+ {
+ // dot
+ if ((dotpos - filename) <= 8)
+ {
+ for (j = 0; j < (dotpos - filename); j++)
+ {
+ mmcfilename[j] = (char) toupper (filename[j]);
+ }
+ for (; j < 8; j++)
+ {
+ mmcfilename[j] = ' ';
+ }
+ // copy 3 char after .
+ mmcfilename[j++] = (char) toupper (dotpos[1]);
+ mmcfilename[j++] = (char) toupper (dotpos[2]);
+ mmcfilename[j++] = (char) toupper (dotpos[3]);
+
+ }
+ else
+ {
+ for (j = 0; j < 6; j++)
+ {
+ mmcfilename[j] = (char) toupper (filename[j]);
+ }
+ mmcfilename[6] = '~';
+ mmcfilename[7] = '1';
+ // copy 3 char after .
+ mmcfilename[8] = (char) toupper (dotpos[1]);
+ mmcfilename[9] = (char) toupper (dotpos[2]);
+ mmcfilename[10] = (char) toupper (dotpos[3]);
+ }
+ filelength = 11;
+ }
+ mmcfilename[11] = '\0';
+
+
+ // search Root Directory for entry filename
+ goout = 0;
+ found = 0;
+ for (j = 0; j < (DataStartSector - RDStartSector); j++)
+ {
+ if (goout == 1)
+ break;
+ response = mmc_readblock (1, (u32) ((RDStartSector + j) * 512), (u32 *) sector, 512, MMCPOLLING);
+ if (response != MMC_OK)
+ {
+ printf ("Error while reading root directory\n");
+ result = FAIL;
+ goto end;
+ }
+
+ for (i = 0; i < 512; i += 32)
+ {
+ strncpy (nomefile, (char *) &sector[i], filelength);
+ if (strcmp (nomefile, mmcfilename) == 0)
+ {
+ mmc_copyByteH (&sector[i + 26], (u8 *) & FileStartCluster, 2);
+ mmc_copyByteH (&sector[i + 28], (u8 *) FileSize, 4);
+ FileStartCluster -= 2;
+ goout = 1;
+ found = 1;
+ break;
+ }
+ if (nomefile[0] == 0)
+ { // end of Root Directory
+ goout = 1;
+ break;
+ }
+ }
+ }
+
+ // size of file : *FileSize ( 32 bits quantum)
+ // number of bytes per sector : BytesPerSector
+ // Beginning of file : FileStartSector
+
+ printf ("Bytes per sector : %d \n", BytesPerSector );
+ printf ("Sectors per cluster : %d \n", SectorsPerCluster );
+ if (found)
+ {
+ u32 remaining = *FileSize ;
+ u32 count;
+ u32 burstsize = BytesPerSector ;
+
+ FileStartSector = ( DataStartSector + (u32)(FileStartCluster * SectorsPerCluster)) ;
+ printf ("Reading file %s from MMC ..., start sector = %d, address 0x%x \n",filename,FileStartSector,address);
+ count = SectorsPerCluster - (FileStartSector % SectorsPerCluster) ;
+ FileStartSector = FileStartSector * BytesPerSector; // the first burst might be different to align of clusters
+
+ do
+ {
+ if ( remaining >= burstsize )
+ { // read straight burst
+
+ k = 0;
+ do
+ {
+ response = mmc_readblock (1, (u32) FileStartSector , (u32 *) mem_address, burstsize , MMCPOLLING);
+ k++;
+
+ } while ((response==MMC_DATA_CRC_FAIL)&&(k<4));
+ if ( k != 1) printf ("!");
+ FileStartSector += burstsize;
+ mem_address += burstsize;
+ remaining -= burstsize;
+ }
+ else
+ { // read burst +1 and perform memcpy
+
+ burstsize = ((remaining + (BytesPerSector-1))/BytesPerSector) * BytesPerSector ;
+ k = 0;
+ do
+ {
+ response = mmc_readblock (1, (u32) FileStartSector , (u32 *) MMCBuffer , burstsize , MMCPOLLING);
+ k++;
+ } while ((response==MMC_DATA_CRC_FAIL)&&(k<4));
+ if ( k != 1) printf ("!");
+ memcpy ((char *) mem_address, (char *)MMCBuffer,remaining);
+ remaining = 0;
+ }
+ if (response != MMC_OK)
+ {
+ printf ("Error while reading file %s\n", filename);
+ result = FAIL;
+ goto end;
+ }
+ } while ( remaining );
+
+ }
+ else
+ {
+ printf ("Unable to find %s on Multi Media Card\n", filename);
+ response = MMC_INVALID_PARAMETER;
+ result = FAIL;
+ goto end;
+ }
+
+end:
+ gpio_altfuncdisable(GPIO_ALT_SD_CARD0, "MMC");
+ response2 = mmc_disable ();
+
+ return response;
+}
+
+t_mmc_error display_file_list (char *extension)
+{
+ u32 i, j, k, goout;
+ u32 FATStartSector;
+ u8 SectorsPerCluster;
+ u32 RDStartSector;
+ u32 DataStartSector;
+ u16 BytesPerSector;
+ u32 BRStartSector;
+ u16 SectorsPerFAT;
+ u16 MaxRDEntries;
+ u16 ReservedSectors;
+ u8 sector[512];
+ t_mmc_error response;
+ t_mmc_error response2;
+ u32 CSD[4];
+ char nomefile[12] = " ";
+ char name[9] = " ";
+ char extent[4] = " ";
+ u32 FileSize;
+
+ //printf("disp:: start\n");
+ gpio_altfuncenable(GPIO_ALT_SD_CARD0, "MMC");
+
+ // Power-on the controller
+ response = mmc_enable ();
+
+ if (response != MMC_OK)
+ {
+ response = mmc_enable (); // This actually IS necessary because it takes time for newly-inserted cards initialize. ~Chris S.
+ if (response != MMC_OK)
+ {
+ printf ("Error in card power on, response is %d\n", response);
+ goto end;
+ }
+ }
+ // Initialise the cards on the bus, if any
+
+ response = mmc_initCard ();
+
+ if (response != MMC_OK)
+ {
+ printf ("1. Error in card initialization\n");
+ goto end;
+ }
+ // Get card info: CID, CSD, RCA registers
+
+ response = mmc_readcsd (CSD);
+
+ if (response != MMC_OK) {
+ printf ("Error while fetching card info\n");
+ goto end;
+ }
+ // Read the MBR
+
+ response = mmc_readblock (1, 0, (u32 *) sector, 512, MMCPOLLING);
+
+ if (response != MMC_OK)
+ {
+ printf ("Error while reading boot record\n");
+ goto end;
+ }
+ if (sector[446] == 0x00 || sector[446] == 0x80)
+ { // found a MBR at the beginning of card
+
+ BRStartSector = sector[454];
+ }
+ else
+ { // BR at the beginning of card
+
+ BRStartSector = 0x00;
+ }
+ // Read the BR
+ response = mmc_readblock (1, (u32) (512 * BRStartSector), (u32 *) & mmc_boot_record, 512, MMCPOLLING);
+
+ k = 0;
+ while (response == MMC_DATA_CRC_FAIL && (k < 2))
+ {
+ response = mmc_readblock (1, (u32) (512 * BRStartSector), (u32 *) & mmc_boot_record, 512, MMCPOLLING);
+ k++;
+ }
+ if (response != MMC_OK)
+ {
+ printf ("Error while reading boot record\n");
+ goto end;
+ }
+ mmc_copyByteH (mmc_boot_record.BytesPerSector, (u8 *) & BytesPerSector, 2);
+ mmc_copyByteH (mmc_boot_record.ReservedSectors, (u8 *) & ReservedSectors, 2);
+ FATStartSector = BRStartSector + ReservedSectors; // the field at offset 15 contains the number of reserved sectors at
+ // the beginning of the media including the boot sector
+
+ mmc_copyByteH (mmc_boot_record.SectorsPerFat, (u8 *) & SectorsPerFAT, 2);
+ SectorsPerCluster = mmc_boot_record.SectorsPerCluster[0];
+ mmc_copyByteH (mmc_boot_record.NumOfRootEntries, (u8 *) & MaxRDEntries, 2);
+
+ FATStartSector += SectorsPerFAT;
+ RDStartSector = FATStartSector + SectorsPerFAT;
+ DataStartSector = RDStartSector + (u32) ((MaxRDEntries * 32) / 512);
+ // search Root Directory for entry filename
+ goout = 0;
+ printf ("file \t\t size\n");
+
+ for (j = 0; j < (DataStartSector - RDStartSector); j++)
+ {
+ printf(" disp:: data start \n");
+ if (goout == 1)
+ {
+ break;
+ }
+ response = mmc_readblock (1, (u32) ((RDStartSector + j) * 512), (u32 *) sector, 512, MMCPOLLING);
+ k = 0;
+ while (response == MMC_DATA_CRC_FAIL && (k < 2))
+ {
+ response = mmc_readblock (1, (u32) ((RDStartSector + j) * 512), (u32 *) sector, 512, MMCPOLLING);
+ k++;
+ }
+ if (response != MMC_OK)
+ {
+ printf ("Error while reading root directory\n");
+ goto end;
+ }
+ for (i = 0; i < 512; i += 32)
+ {
+ strncpy (nomefile, (char *) &sector[i], 11);
+ if (nomefile[0] == 0) // end of Root Directory
+ {
+ goout = 1;
+ break;
+ }
+ if (nomefile[0] != 0xE5) // not deleted file only
+ {
+ for (k = 0; k < 3; k++)
+ {
+ extent[k] = (char) toupper (extension[k]);
+ }
+ if ((strncmp (&nomefile[8], extent, strlen (extension)) == 0) || (*extension == '*'))
+ {
+ mmc_copyByteH (&sector[i + 28], (u8 *) & FileSize, 4);
+ k = 0;
+ while ((nomefile[k] != 0x20) && (k < 8))
+ {
+ name[k] = (char) tolower (nomefile[k]);
+ k++;
+ }
+ name[k] = '\0';
+ for (k = 0; k < 3; k++)
+ {
+ extent[k] = (char) tolower (nomefile[k + 8]);
+ }
+ printf ("%s.%s \t %10ld\n", name, extent, FileSize);
+ }
+ }
+ }
+ }
+end:
+ gpio_altfuncdisable(GPIO_ALT_SD_CARD0, "MMC");
+ response2 = mmc_disable ();
+ //printf("disp:: done \n");
+ return response;
+}
+
+/*
+ * command line commands
+ */
+
+static char mmc_cmdbuffer[1024] ;
+
+int copy_file_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unsigned long address;
+ unsigned long filesize;
+ int load_result;
+ char filename[30];
+
+ strcpy(filename , argv[1]);
+ address = simple_strtoul (argv[2], 0, 16);
+
+ printf("copy_file_mmc : filename = %s\n", filename);
+ printf("copy_file_mmc : address = %x\n", address);
+
+ load_result = mmc_read_file(filename, address, &filesize);
+ if (load_result != 0)
+ {
+ printf("copy_file_mmc error : in loading file \n");
+ }
+ return(load_result);
+}
+
+int mmc_read_cmd_file (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ unsigned long filesize;
+ int load_result;
+
+ load_result = mmc_read_file("command.txt",
+ (unsigned long)&mmc_cmdbuffer, &filesize);
+ if (load_result != 0) {
+ printf("mmc_read_cmd_file error : in loading file \n");
+ } else {
+ setenv ("bootcmd", mmc_cmdbuffer);
+ }
+ return(load_result);
+}
+
+
+U_BOOT_CMD(
+ copy_file_mmc, 3, 0, copy_file_mmc,
+ "- copy file from mmc card\n",
+ "filename address\n"
+ " - load binary file from the MMC/SD card to a memory address\n"
+);
+
+
+U_BOOT_CMD(
+ mmc_read_cmd_file, 1, 0, mmc_read_cmd_file,
+ "- copy command file from mmc card\n",
+ NULL
+);
+
+/* ------------------------------- End of file ---------------------------- */